diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java index bea3d0ebe6a3..413720c5e483 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java @@ -1200,6 +1200,16 @@ public Mono reconstructMetadataFromGitRepo( return metadataMono.subscribeOn(scheduler); } + @Override + public Mono reconstructMetadataFromGitRepository(Path repoSuffix) { + Mono metadataMono = Mono.fromCallable(() -> { + Path baseRepoPath = Paths.get(gitServiceConfig.getGitRootPath()).resolve(repoSuffix); + return fileOperations.readFile(baseRepoPath.resolve(CommonConstants.METADATA + JSON_EXTENSION)); + }); + + return metadataMono.subscribeOn(scheduler); + } + @Override public Mono reconstructPageFromGitRepo( String pageName, String branchName, Path baseRepoSuffixPath, Boolean resetToLastCommitRequired) { diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java index c655ef2bfbe8..bf68ce6171b2 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java @@ -71,6 +71,8 @@ Mono reconstructMetadataFromGitRepo( Path repoSuffixPath, Boolean isResetToLastCommitRequired); + Mono reconstructMetadataFromGitRepository(Path repoSuffix); + Mono reconstructPageFromGitRepo( String pageName, String branchName, Path repoSuffixPath, Boolean checkoutRequired); diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/GitConstantsCE.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/GitConstantsCE.java index 9aa0c308b8f4..186f01311fd3 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/GitConstantsCE.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/GitConstantsCE.java @@ -10,6 +10,7 @@ public class GitConstantsCE { public static final String ACTION_COLLECTION_LIST = "actionCollectionList"; public static final String README_FILE_NAME = "README.md"; + public static final String ARTIFACT_JSON_TYPE = "artifactJsonType"; public static final String FIRST_COMMIT = "System added readme file"; public static final String DEFAULT_COMMIT_MESSAGE = "System generated commit, "; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/FieldNameCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/FieldNameCE.java index ab487f3e12e5..2ffdc1ba5c7f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/FieldNameCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/FieldNameCE.java @@ -71,6 +71,7 @@ public class FieldNameCE { public static final String ACTIONS = "actions"; public static final String ASSET = "asset"; public static final String APPLICATION = "application"; + public static final String ARTIFACT = "artifact"; public static final String SOURCE_APPLICATION = "sourceApplication"; public static final String COMMENT = "comment"; public static final String COMMENT_THREAD = "commentThread"; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Theme.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Theme.java index 3c82a0e2b49f..592d3c686291 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Theme.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Theme.java @@ -49,7 +49,8 @@ public class Theme extends BaseDomain { @JsonProperty("isSystemTheme") // manually setting property name to make sure it's compatible with Gson @JsonView({Views.Public.class, Git.class}) - private boolean isSystemTheme = false; // should be false by default + // The primitive is changed to wrapper because of serialization - deserialization issues + private Boolean isSystemTheme = false; // should be false by default @Data @AllArgsConstructor @@ -59,6 +60,21 @@ public static class Colors { private String backgroundColor; } + public void setSystemTheme(boolean isSystemTheme) { + this.isSystemTheme = isSystemTheme; + } + + @JsonView({Views.Internal.class}) + public Boolean getSystemTheme() { + return this.isSystemTheme; + } + + // To be deleted in later on refactors + @JsonView({Views.Internal.class}) + public Boolean isSystemTheme() { + return this.isSystemTheme; + } + @Override public void sanitiseToExportDBObject() { this.setId(null); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java index 58696d9cf5af..988ed7a00939 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java @@ -24,6 +24,9 @@ public interface CentralGitServiceCE { Mono importArtifactFromGit( String workspaceId, GitConnectDTO gitConnectDTO, ArtifactType artifactType, GitType gitType); + Mono importArtifactFromGit( + String workspaceId, GitConnectDTO gitConnectDTO, GitType gitType); + Mono connectArtifactToGit( String baseArtifactId, ArtifactType artifactType, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index 58059e906d57..f6ab0a0862c5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -85,6 +85,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.TimeoutException; import static com.appsmith.external.git.constants.ce.GitConstantsCE.DEFAULT_COMMIT_MESSAGE; @@ -143,6 +144,204 @@ protected Mono isRepositoryLimitReachedForWorkspace(String workspaceId, return gitPrivateRepoHelper.isRepoLimitReached(workspaceId, true); } + @Override + public Mono importArtifactFromGit( + String workspaceId, GitConnectDTO gitConnectDTO, GitType gitType) { + if (!StringUtils.hasText(workspaceId)) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID)); + } + + GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); + Set errors = gitHandlingService.validateGitConnectDTO(gitConnectDTO); + + if (!CollectionUtils.isEmpty(errors)) { + return Mono.error(new AppsmithException( + AppsmithError.INVALID_PARAMETER, errors.stream().findAny().get())); + } + + final String repoName = gitHandlingService.getRepoName(gitConnectDTO); + + // since at this point in the import flow, there is no context about the artifact type + // it needs to be retrieved from the fetched repository itself. however, in order to retrieve + // the artifact type from repository, the repository needs to be saved. + // for saving the repo an identifier is required (which usually is the artifact id); + // however, the artifact could only be generated after the artifact type is known. + // hence this is a temporary placeholder to hold the repository and it's components + String placeholder = "temp" + UUID.randomUUID(); + ArtifactJsonTransformationDTO tempJsonTransformationDTO = + new ArtifactJsonTransformationDTO(workspaceId, placeholder, repoName); + + ArtifactJsonTransformationDTO jsonDTOPostRefCreation = + new ArtifactJsonTransformationDTO(workspaceId, placeholder, repoName); + + Mono isRepositoryPrivateMonoCached = + gitHandlingService.isRepoPrivate(gitConnectDTO).cache(); + + Mono isRepositoryLimitReachedForWorkspaceMono = isRepositoryPrivateMonoCached.flatMap( + isRepositoryPrivate -> isRepositoryLimitReachedForWorkspace(workspaceId, isRepositoryPrivate)); + + Mono gitAuthMonoCached = gitHandlingService.getGitAuthForUser().cache(); + + Mono blankArtifactForImportMono = isRepositoryLimitReachedForWorkspaceMono + .flatMap(isLimitReachedForPrivateRepositories -> { + if (!TRUE.equals(isLimitReachedForPrivateRepositories)) { + return gitAuthMonoCached; + } + + return gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_IMPORT, + workspaceId, + AppsmithError.GIT_APPLICATION_LIMIT_ERROR.getErrorType(), + AppsmithError.GIT_APPLICATION_LIMIT_ERROR.getMessage(), + true, + false) + .then(Mono.error(new AppsmithException(AppsmithError.GIT_APPLICATION_LIMIT_ERROR))); + }) + .flatMap(gitAuth -> { + return gitHandlingService + .fetchRemoteRepository(gitConnectDTO, gitAuth, tempJsonTransformationDTO) + .flatMap(defaultBranch -> { + return Mono.zip( + Mono.just(defaultBranch), + gitHandlingService.obtainArtifactTypeFromGitRepository( + tempJsonTransformationDTO), + isRepositoryPrivateMonoCached, + Mono.just(gitAuth)); + }); + }) + .flatMap(tuple4 -> { + String defaultBranch = tuple4.getT1(); + ArtifactType artifactType = tuple4.getT2(); + Boolean isRepoPrivate = tuple4.getT3(); + GitAuth gitAuth = tuple4.getT4(); + + GitArtifactHelper contextHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + AclPermission workspacePermission = contextHelper.getWorkspaceArtifactCreationPermission(); + + Mono workspaceMono = workspaceService + .findById(workspaceId, workspacePermission) + .switchIfEmpty(Mono.error(new AppsmithException( + AppsmithError.NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId))); + + return workspaceMono + .flatMap(workspace -> contextHelper.createArtifactForImport(workspaceId, repoName)) + .map(baseArtifact -> { + GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); + gitArtifactMetadata.setGitAuth(gitAuth); + gitArtifactMetadata.setDefaultArtifactId(baseArtifact.getId()); + gitArtifactMetadata.setDefaultBranchName(defaultBranch); + gitArtifactMetadata.setRefName(defaultBranch); + gitArtifactMetadata.setRepoName(repoName); + gitArtifactMetadata.setIsRepoPrivate(isRepoPrivate); + gitArtifactMetadata.setLastCommittedAt(Instant.now()); + + gitHandlingService.setRepositoryDetailsInGitArtifactMetadata( + gitConnectDTO, gitArtifactMetadata); + baseArtifact.setGitArtifactMetadata(gitArtifactMetadata); + return baseArtifact; + }); + }); + + Mono containerArtifactForImport = Mono.usingWhen( + blankArtifactForImportMono, + baseArtifact -> { + GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); + String defaultBranch = baseGitMetadata.getDefaultBranchName(); + + jsonDTOPostRefCreation.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId()); + jsonDTOPostRefCreation.setRefType(RefType.branch); + jsonDTOPostRefCreation.setRefName(defaultBranch); + jsonDTOPostRefCreation.setArtifactType(baseArtifact.getArtifactType()); + + return Mono.just(baseArtifact); + }, + // in any case repository details needs to be updated with the base artifact id + baseArtifact -> + gitHandlingService.updateImportedRepositoryDetails(baseArtifact, tempJsonTransformationDTO)); + + Mono importGitArtifactMono = Mono.usingWhen( + containerArtifactForImport, + baseArtifact -> { + GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); + String defaultBranch = baseGitMetadata.getDefaultBranchName(); + GitArtifactHelper gitArtifactHelper = + gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType()); + + Mono> datasourceMono = datasourceService + .getAllByWorkspaceIdWithStorages(workspaceId, datasourcePermission.getEditPermission()) + .collectList(); + + Mono> pluginMono = + pluginService.getDefaultPlugins().collectList(); + + Mono artifactExchangeJsonMono = gitHandlingService + .reconstructArtifactJsonFromGitRepository(jsonDTOPostRefCreation) + .onErrorResume(error -> { + log.error("Error while constructing artifact from git repo", error); + return Mono.error( + new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, error.getMessage())); + }); + + return Mono.zip(artifactExchangeJsonMono, datasourceMono, pluginMono) + .flatMap(data -> { + ArtifactExchangeJson artifactExchangeJson = data.getT1(); + List datasourceList = data.getT2(); + List pluginList = data.getT3(); + + if (artifactExchangeJson.getArtifact() == null + || gitArtifactHelper.isContextInArtifactEmpty(artifactExchangeJson)) { + return Mono.error(new AppsmithException( + AppsmithError.GIT_ACTION_FAILED, + "import", + "Cannot import artifact from an empty repo")); + } + + // If there is an existing datasource with the same name but a different type from that + // in the repo, the import api should fail + // TODO: change the implementation to compare datasource with gitSyncIds instead. + if (checkIsDatasourceNameConflict( + datasourceList, artifactExchangeJson.getDatasourceList(), pluginList)) { + return Mono.error(new AppsmithException( + AppsmithError.GIT_ACTION_FAILED, + "import", + "Datasource already exists with the same name")); + } + + artifactExchangeJson.getArtifact().setGitArtifactMetadata(baseGitMetadata); + return importService + .importArtifactInWorkspaceFromGit( + workspaceId, baseArtifact.getId(), artifactExchangeJson, defaultBranch) + .onErrorResume(throwable -> { + log.error("Error in importing the artifact {}", baseArtifact.getId()); + return Mono.error(new AppsmithException( + AppsmithError.GIT_FILE_SYSTEM_ERROR, throwable.getMessage())); + }); + }) + .flatMap(artifact -> gitArtifactHelper.publishArtifact(artifact, false)) + .flatMap(artifact -> importService.getArtifactImportDTO( + artifact.getWorkspaceId(), artifact.getId(), artifact, artifact.getArtifactType())); + }, + baseArtifact -> { + // on success send analytics + return gitAnalyticsUtils.addAnalyticsForGitOperation( + AnalyticsEvents.GIT_IMPORT, + baseArtifact, + baseArtifact.getGitArtifactMetadata().getIsRepoPrivate()); + }, + (baseArtifact, throwableError) -> { + // on error + return deleteArtifactCreatedFromGitImport(jsonDTOPostRefCreation, gitType); + }, + baseArtifact -> { + // on publisher cancellation + return deleteArtifactCreatedFromGitImport(jsonDTOPostRefCreation, gitType); + }); + + return Mono.create( + sink -> importGitArtifactMono.subscribe(sink::success, sink::error, null, sink.currentContext())); + } + @Override public Mono importArtifactFromGit( String workspaceId, GitConnectDTO gitConnectDTO, ArtifactType artifactType, GitType gitType) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java index c52960207159..f26c7c3ef726 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java @@ -5,6 +5,7 @@ import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.git.dtos.FetchRemoteDTO; import com.appsmith.git.dto.CommitDTO; +import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.domains.Artifact; import com.appsmith.server.domains.GitArtifactMetadata; import com.appsmith.server.domains.GitAuth; @@ -15,6 +16,7 @@ import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; +import java.nio.file.Path; import java.util.List; import java.util.Set; @@ -33,6 +35,15 @@ public interface GitHandlingServiceCE { Boolean isGitAuthInvalid(GitAuth gitAuth); + // TODO: use only the required params + Mono updateImportedRepositoryDetails( + Artifact baseArtifact, ArtifactJsonTransformationDTO jsonTransformationDTO); + + Mono obtainArtifactTypeFromGitRepository(ArtifactJsonTransformationDTO jsonTransformationDTO); + + Mono fetchRemoteRepository( + GitConnectDTO gitConnectDTO, GitAuth gitAuth, ArtifactJsonTransformationDTO jsonTransformationDTO); + Mono fetchRemoteRepository( GitConnectDTO gitConnectDTO, GitAuth gitAuth, Artifact artifact, String repoName); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java index 2ea2a29d583c..785fffa64ea3 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java @@ -1,7 +1,6 @@ package com.appsmith.server.git.controllers; import com.appsmith.external.views.Views; -import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.constants.Url; import com.appsmith.server.domains.GitAuth; import com.appsmith.server.domains.GitProfile; @@ -88,7 +87,7 @@ public Mono> importArtifactFromGit( // TODO: remove artifact type from methods. return centralGitService - .importArtifactFromGit(workspaceId, gitConnectDTO, ArtifactType.APPLICATION, GIT_TYPE) + .importArtifactFromGit(workspaceId, gitConnectDTO, GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null)); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index 129a7b62cbaf..6b8f5eb355a5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -164,6 +164,67 @@ public Boolean isGitAuthInvalid(GitAuth gitAuth) { return !StringUtils.hasText(gitAuth.getPrivateKey()) || !StringUtils.hasText(gitAuth.getPublicKey()); } + public Mono fetchRemoteRepository( + GitConnectDTO gitConnectDTO, GitAuth gitAuth, ArtifactJsonTransformationDTO jsonTransformationDTO) { + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String placeHolder = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + Path temporaryStorage = Path.of(workspaceId, placeHolder, repoName); + + return fsGitHandler + .cloneRemoteIntoArtifactRepo( + temporaryStorage, gitConnectDTO.getRemoteUrl(), gitAuth.getPrivateKey(), gitAuth.getPublicKey()) + .onErrorResume(error -> { + log.error("Error in cloning the remote repo, {}", error.getMessage()); + return gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_IMPORT, + workspaceId, + error.getClass().getName(), + error.getMessage(), + false, + false) + .flatMap(user -> commonGitFileUtils.deleteLocalRepo(temporaryStorage)) + .flatMap(isDeleted -> { + if (error instanceof TransportException) { + return Mono.error( + new AppsmithException(AppsmithError.INVALID_GIT_SSH_CONFIGURATION)); + } else if (error instanceof InvalidRemoteException) { + return Mono.error( + new AppsmithException(AppsmithError.INVALID_PARAMETER, "remote url")); + } else if (error instanceof TimeoutException) { + return Mono.error(new AppsmithException(AppsmithError.GIT_EXECUTION_TIMEOUT)); + } + return Mono.error(new AppsmithException( + AppsmithError.GIT_ACTION_FAILED, "clone", error.getMessage())); + }); + }); + } + + public Mono obtainArtifactTypeFromGitRepository(ArtifactJsonTransformationDTO jsonTransformationDTO) { + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String placeHolder = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + Path temporaryStorage = Path.of(workspaceId, placeHolder, repoName); + + return commonGitFileUtils.getArtifactJsonTypeOfRepository(temporaryStorage); + } + + @Override + public Mono updateImportedRepositoryDetails( + Artifact baseArtifact, ArtifactJsonTransformationDTO jsonTransformationDTO) { + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String placeHolder = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + Path temporaryStorage = Path.of(workspaceId, placeHolder, repoName); + + ArtifactType artifactType = baseArtifact.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + Path newPath = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifact.getId(), repoName); + + return commonGitFileUtils.moveArtifactFromTemporaryToBaseArtifactIdRepository(temporaryStorage, newPath); + } + @Override public Mono fetchRemoteRepository( GitConnectDTO gitConnectDTO, GitAuth gitAuth, Artifact artifact, String repoName) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java index b5dc2bb812b0..63e03da64c58 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java @@ -72,13 +72,46 @@ public Mono addAnalyticsForGitOperation( Boolean isSystemGenerated, Boolean isMergeable) { - String branchName = artifact.getGitArtifactMetadata() != null - ? artifact.getGitArtifactMetadata().getRefName() - : null; + String branchName = (artifact == null || artifact.getGitArtifactMetadata() == null) + ? null + : artifact.getGitArtifactMetadata().getRefName(); return addAnalyticsForGitOperation( event, artifact, errorType, errorMessage, isRepoPrivate, isSystemGenerated, isMergeable, branchName); } + public Mono addAnalyticsForGitOperation( + AnalyticsEvents event, + String workspaceId, + String errorType, + String errorMessage, + Boolean isRepoPrivate, + Boolean isSystemGenerated) { + + Map analyticsProps = new HashMap<>(); + + // Do not include the error data points in the map for success states + if (StringUtils.hasText(errorMessage) || StringUtils.hasText(errorType)) { + analyticsProps.put("errorMessage", errorMessage); + analyticsProps.put("errorType", errorType); + } + + analyticsProps.putAll(Map.of( + FieldName.WORKSPACE_ID, + defaultIfNull(workspaceId, ""), + FieldName.ARTIFACT_ID, + defaultIfNull("", ""), + "isRepoPrivate", + defaultIfNull(isRepoPrivate, ""), + "isSystemGenerated", + defaultIfNull(isSystemGenerated, ""))); + + final Map eventData = Map.of(FieldName.APP_MODE, ApplicationMode.EDIT.toString()); + analyticsProps.put(FieldName.EVENT_DATA, eventData); + return sessionUserService + .getCurrentUser() + .flatMap(user -> analyticsService.sendEvent(event.getEventName(), user.getUsername(), analyticsProps)); + } + public Mono addAnalyticsForGitOperation( AnalyticsEvents event, Artifact artifact, @@ -88,10 +121,12 @@ public Mono addAnalyticsForGitOperation( Boolean isSystemGenerated, Boolean isMergeable, String branchName) { - GitArtifactMetadata gitData = artifact.getGitArtifactMetadata(); + Map analyticsProps = new HashMap<>(); - if (gitData != null) { - analyticsProps.put(FieldName.APPLICATION_ID, gitData.getDefaultArtifactId()); + if (artifact != null && artifact.getGitArtifactMetadata() != null) { + GitArtifactMetadata gitData = artifact.getGitArtifactMetadata(); + analyticsProps.put(FieldName.ARTIFACT_ID, gitData.getDefaultArtifactId()); + analyticsProps.put("artifactType", artifact.getArtifactType()); analyticsProps.put("appId", gitData.getDefaultArtifactId()); analyticsProps.put(FieldName.BRANCH_NAME, branchName); analyticsProps.put(FieldName.GIT_HOSTING_PROVIDER, GitUtils.getGitProviderName(gitData.getRemoteUrl())); @@ -113,14 +148,14 @@ public Mono addAnalyticsForGitOperation( analyticsProps.putAll(Map.of( "workspaceId", defaultIfNull(artifact.getWorkspaceId(), ""), - "branchApplicationId", + "branchedArtifactId", defaultIfNull(artifact.getId(), ""), "isRepoPrivate", defaultIfNull(isRepoPrivate, ""), "isSystemGenerated", defaultIfNull(isSystemGenerated, ""))); final Map eventData = - Map.of(FieldName.APP_MODE, ApplicationMode.EDIT.toString(), FieldName.APPLICATION, artifact); + Map.of(FieldName.APP_MODE, ApplicationMode.EDIT.toString(), FieldName.ARTIFACT, artifact); analyticsProps.put(FieldName.EVENT_DATA, eventData); return sessionUserService.getCurrentUser().flatMap(user -> analyticsService .sendEvent(event.getEventName(), user.getUsername(), analyticsProps) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java index ea9efe296082..9cfe711219fa 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java @@ -2,6 +2,7 @@ import com.appsmith.external.git.FileInterface; import com.appsmith.external.git.operations.FileOperations; +import com.appsmith.git.configurations.GitServiceConfig; import com.appsmith.git.files.FileUtilsImpl; import com.appsmith.server.actioncollections.base.ActionCollectionService; import com.appsmith.server.dtos.ApplicationJson; @@ -22,6 +23,7 @@ public class CommonGitFileUtils extends CommonGitFileUtilsCE { public CommonGitFileUtils( ArtifactGitFileUtils applicationGitFileUtils, + GitServiceConfig gitServiceConfig, FileInterface fileUtils, FileOperations fileOperations, AnalyticsService analyticsService, @@ -32,6 +34,7 @@ public CommonGitFileUtils( ObjectMapper objectMapper) { super( applicationGitFileUtils, + gitServiceConfig, fileUtils, fileOperations, analyticsService, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java index eb878cbba5ec..bd0849e28971 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java @@ -14,6 +14,7 @@ import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.DatasourceStorage; import com.appsmith.external.models.PluginType; +import com.appsmith.git.configurations.GitServiceConfig; import com.appsmith.git.constants.CommonConstants; import com.appsmith.git.files.FileUtilsImpl; import com.appsmith.server.actioncollections.base.ActionCollectionService; @@ -53,6 +54,7 @@ import reactor.core.scheduler.Schedulers; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; @@ -62,6 +64,7 @@ import java.util.stream.Collector; import java.util.stream.Collectors; +import static com.appsmith.external.git.constants.ce.GitConstantsCE.ARTIFACT_JSON_TYPE; import static com.appsmith.external.git.constants.ce.GitConstantsCE.GitCommandConstantsCE.CHECKOUT_BRANCH; import static com.appsmith.external.git.constants.ce.GitConstantsCE.RECONSTRUCT_PAGE; import static com.appsmith.git.constants.CommonConstants.CLIENT_SCHEMA_VERSION; @@ -79,6 +82,7 @@ import static com.appsmith.git.constants.ce.GitDirectoriesCE.JS_LIB_DIRECTORY; import static com.appsmith.git.constants.ce.GitDirectoriesCE.PAGE_DIRECTORY; import static com.appsmith.git.files.FileUtilsCEImpl.getJsLibFileName; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.springframework.util.StringUtils.hasText; @Slf4j @@ -87,6 +91,7 @@ public class CommonGitFileUtilsCE { protected final ArtifactGitFileUtils applicationGitFileUtils; + protected final GitServiceConfig gitServiceConfig; private final FileInterface fileUtils; private final FileOperations fileOperations; private final AnalyticsService analyticsService; @@ -104,6 +109,7 @@ public class CommonGitFileUtilsCE { public CommonGitFileUtilsCE( ArtifactGitFileUtils applicationGitFileUtils, + GitServiceConfig gitServiceConfig, FileInterface fileUtils, FileOperations fileOperations, AnalyticsService analyticsService, @@ -113,6 +119,7 @@ public CommonGitFileUtilsCE( JsonSchemaVersions jsonSchemaVersions, ObjectMapper objectMapper) { this.applicationGitFileUtils = applicationGitFileUtils; + this.gitServiceConfig = gitServiceConfig; this.fileUtils = fileUtils; this.fileOperations = fileOperations; this.analyticsService = analyticsService; @@ -779,6 +786,53 @@ public Mono> reconstructMetadataFromRepo( }); } + public Mono moveArtifactFromTemporaryToBaseArtifactIdRepository( + Path currentRepositoryPath, Path newRepositoryPath) { + Path currentGitPath = Path.of(gitServiceConfig.getGitRootPath()).resolve(currentRepositoryPath); + Path targetPath = Path.of(gitServiceConfig.getGitRootPath()).resolve(newRepositoryPath); + + return Mono.fromCallable(() -> { + if (!Files.exists(targetPath)) { + Files.createDirectories(targetPath); + } + + return Files.move(currentGitPath, targetPath, REPLACE_EXISTING); + }) + .subscribeOn(Schedulers.boundedElastic()); + } + + public Mono getArtifactJsonTypeOfRepository(Path repoSuffix) { + Mono artifactTypeMono = fileUtils + .reconstructMetadataFromGitRepository(repoSuffix) + .flatMap(metadata -> { + Gson gson = new Gson(); + JsonObject metadataJsonObject = + gson.toJsonTree(metadata, Object.class).getAsJsonObject(); + + if (metadataJsonObject == null) { + log.error( + "Error in retrieving the metadata from the file system for repository {}", repoSuffix); + return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR)); + } + + JsonElement artifactJsonType = metadataJsonObject.get(ARTIFACT_JSON_TYPE); + + if (artifactJsonType == null) { + log.error( + "artifactJsonType attribute not found in the metadata file for repository {}", + repoSuffix); + return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR)); + } + + return Mono.just(artifactJsonType.getAsString()); + }) + .flatMap(artifactJsonType -> { + return Mono.justOrEmpty(ArtifactType.valueOf(artifactJsonType)); + }); + + return Mono.create(sink -> artifactTypeMono.subscribe(sink::success, sink::error, null, sink.currentContext())); + } + /** * Provides the server schema version in the application json for the given branch * 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 426f57d80057..dc6ee3856570 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 @@ -161,8 +161,9 @@ public Mono getApplicationByGitBranchAndBaseApplicationId( public Flux getApplicationByGitBaseApplicationId(String baseApplicationId, AclPermission permission) { return queryBuilder() - .criteria( - Bridge.equal(Application.Fields.gitApplicationMetadata_defaultApplicationId, baseApplicationId)) + .criteria(Bridge.or( + Bridge.equal(Application.Fields.gitApplicationMetadata_defaultApplicationId, baseApplicationId), + Bridge.equal(Application.Fields.gitApplicationMetadata_defaultArtifactId, baseApplicationId))) .permission(permission) .all(); }