feat: Add API to support partial import (#28357)
## Description > PR to support partial import changes #### PR fixes following issue(s) Fixes #28223 #### Type of change - New feature (non-breaking change which adds functionality) ## Testing #### How Has This Been Tested? - [ ] Manual ## Checklist: #### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] 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 - [x] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
parent
62383c975c
commit
08e0cc0431
|
|
@ -84,7 +84,9 @@ public enum AnalyticsEvents {
|
|||
DS_TEST_EVENT_FAILED("Test_Datasource_Failed"),
|
||||
|
||||
GIT_STALE_FILE_LOCK_DELETED,
|
||||
SERVER_SETUP_COMPLETE("server_setup_complete");
|
||||
SERVER_SETUP_COMPLETE("server_setup_complete"),
|
||||
|
||||
PARTIAL_IMPORT;
|
||||
|
||||
private final String eventName;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.appsmith.server.exports.internal.ExportApplicationService;
|
|||
import com.appsmith.server.exports.internal.PartialExportService;
|
||||
import com.appsmith.server.fork.internal.ApplicationForkingService;
|
||||
import com.appsmith.server.imports.internal.ImportApplicationService;
|
||||
import com.appsmith.server.imports.internal.PartialImportService;
|
||||
import com.appsmith.server.services.ApplicationPageService;
|
||||
import com.appsmith.server.services.ApplicationService;
|
||||
import com.appsmith.server.services.ApplicationSnapshotService;
|
||||
|
|
@ -27,7 +28,8 @@ public class ApplicationController extends ApplicationControllerCE {
|
|||
ExportApplicationService exportApplicationService,
|
||||
ThemeService themeService,
|
||||
ApplicationSnapshotService applicationSnapshotService,
|
||||
PartialExportService partialExportService) {
|
||||
PartialExportService partialExportService,
|
||||
PartialImportService partialImportService) {
|
||||
super(
|
||||
service,
|
||||
applicationPageService,
|
||||
|
|
@ -37,6 +39,7 @@ public class ApplicationController extends ApplicationControllerCE {
|
|||
exportApplicationService,
|
||||
themeService,
|
||||
applicationSnapshotService,
|
||||
partialExportService);
|
||||
partialExportService,
|
||||
partialImportService);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.appsmith.server.dtos.ApplicationAccessDTO;
|
|||
import com.appsmith.server.dtos.ApplicationImportDTO;
|
||||
import com.appsmith.server.dtos.ApplicationPagesDTO;
|
||||
import com.appsmith.server.dtos.GitAuthDTO;
|
||||
import com.appsmith.server.dtos.PartialExportFileDTO;
|
||||
import com.appsmith.server.dtos.ReleaseItemsDTO;
|
||||
import com.appsmith.server.dtos.ResponseDTO;
|
||||
import com.appsmith.server.dtos.UserHomepageDTO;
|
||||
|
|
@ -21,6 +22,7 @@ import com.appsmith.server.exports.internal.ExportApplicationService;
|
|||
import com.appsmith.server.exports.internal.PartialExportService;
|
||||
import com.appsmith.server.fork.internal.ApplicationForkingService;
|
||||
import com.appsmith.server.imports.internal.ImportApplicationService;
|
||||
import com.appsmith.server.imports.internal.PartialImportService;
|
||||
import com.appsmith.server.services.ApplicationPageService;
|
||||
import com.appsmith.server.services.ApplicationService;
|
||||
import com.appsmith.server.services.ApplicationSnapshotService;
|
||||
|
|
@ -64,8 +66,8 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
|
|||
private final ExportApplicationService exportApplicationService;
|
||||
private final ThemeService themeService;
|
||||
private final ApplicationSnapshotService applicationSnapshotService;
|
||||
|
||||
private final PartialExportService partialExportService;
|
||||
private final PartialImportService partialImportService;
|
||||
|
||||
@Autowired
|
||||
public ApplicationControllerCE(
|
||||
|
|
@ -77,7 +79,8 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
|
|||
ExportApplicationService exportApplicationService,
|
||||
ThemeService themeService,
|
||||
ApplicationSnapshotService applicationSnapshotService,
|
||||
PartialExportService partialExportService) {
|
||||
PartialExportService partialExportService,
|
||||
PartialImportService partialImportService) {
|
||||
super(service);
|
||||
this.applicationPageService = applicationPageService;
|
||||
this.applicationFetcher = applicationFetcher;
|
||||
|
|
@ -87,6 +90,7 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
|
|||
this.themeService = themeService;
|
||||
this.applicationSnapshotService = applicationSnapshotService;
|
||||
this.partialExportService = partialExportService;
|
||||
this.partialImportService = partialImportService;
|
||||
}
|
||||
|
||||
@JsonView(Views.Public.class)
|
||||
|
|
@ -368,20 +372,34 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
|
|||
}
|
||||
|
||||
@JsonView(Views.Public.class)
|
||||
@PostMapping("/export/partial/{applicationId}/{pageId}")
|
||||
@PostMapping(value = "/export/partial/{applicationId}/{pageId}", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Mono<ResponseEntity<Object>> exportApplicationPartially(
|
||||
@PathVariable String applicationId,
|
||||
@PathVariable String pageId,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName,
|
||||
@RequestBody MultiValueMap<String, String> params,
|
||||
@RequestBody String widgets) {
|
||||
@Valid @RequestBody PartialExportFileDTO fileDTO) {
|
||||
// params - contains ids of jsLib, actions and datasourceIds to be exported
|
||||
return partialExportService
|
||||
.getPartialExportResources(applicationId, pageId, branchName, params, widgets)
|
||||
.getPartialExportResources(applicationId, pageId, branchName, fileDTO)
|
||||
.map(fetchedResource -> {
|
||||
HttpHeaders responseHeaders = fetchedResource.getHttpHeaders();
|
||||
Object applicationResource = fetchedResource.getApplicationResource();
|
||||
return new ResponseEntity<>(applicationResource, responseHeaders, HttpStatus.OK);
|
||||
});
|
||||
}
|
||||
|
||||
@JsonView(Views.Public.class)
|
||||
@PostMapping(
|
||||
value = "/import/partial/{workspaceId}/{applicationId}",
|
||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public Mono<ResponseDTO<Application>> importApplicationPartially(
|
||||
@RequestPart("file") Mono<Part> fileMono,
|
||||
@PathVariable String workspaceId,
|
||||
@PathVariable String applicationId,
|
||||
@RequestParam String pageId,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
|
||||
return fileMono.flatMap(fileData -> partialImportService.importResourceInPage(
|
||||
workspaceId, applicationId, pageId, branchName, fileData))
|
||||
.map(fetchedResource -> new ResponseDTO<>(HttpStatus.OK.value(), fetchedResource, null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.appsmith.server.dtos;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PartialExportFileDTO {
|
||||
|
||||
List<String> actionList = new ArrayList<>();
|
||||
|
||||
List<String> actionCollectionList = new ArrayList<>();
|
||||
|
||||
List<String> customJsLib = new ArrayList<>();
|
||||
|
||||
List<String> datasourceList = new ArrayList<>();
|
||||
|
||||
String widget = "";
|
||||
}
|
||||
|
|
@ -1,14 +1,10 @@
|
|||
package com.appsmith.server.exports.internal;
|
||||
|
||||
import com.appsmith.server.dtos.ExportFileDTO;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import com.appsmith.server.dtos.PartialExportFileDTO;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface PartialExportServiceCE {
|
||||
Mono<ExportFileDTO> getPartialExportResources(
|
||||
String applicationId,
|
||||
String pageId,
|
||||
String branchName,
|
||||
MultiValueMap<String, String> params,
|
||||
String widgets);
|
||||
String applicationId, String pageId, String branchName, PartialExportFileDTO partialExportFileDTO);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.appsmith.server.dtos.ApplicationJson;
|
|||
import com.appsmith.server.dtos.ExportFileDTO;
|
||||
import com.appsmith.server.dtos.ExportingMetaDTO;
|
||||
import com.appsmith.server.dtos.MappedExportableResourcesDTO;
|
||||
import com.appsmith.server.dtos.PartialExportFileDTO;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import com.appsmith.server.exports.exportable.ExportableService;
|
||||
|
|
@ -31,12 +32,10 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.springframework.http.ContentDisposition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.appsmith.server.constants.ResourceModes.EDIT;
|
||||
|
|
@ -60,11 +59,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
|
||||
@Override
|
||||
public Mono<ExportFileDTO> getPartialExportResources(
|
||||
String applicationId,
|
||||
String pageId,
|
||||
String branchName,
|
||||
MultiValueMap<String, String> params,
|
||||
String widgets) {
|
||||
String applicationId, String pageId, String branchName, PartialExportFileDTO partialExportFileDTO) {
|
||||
/*
|
||||
* Params has ids for actions, customJsLibs and datasource
|
||||
* Export the resources based on the value of these entities
|
||||
|
|
@ -96,21 +91,25 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
return applicationMono
|
||||
.flatMap(application -> {
|
||||
applicationJson.setExportedApplication(application);
|
||||
return pluginExportableService.getExportableEntities(
|
||||
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson);
|
||||
return pluginExportableService
|
||||
.getExportableEntities(
|
||||
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson)
|
||||
.thenReturn(applicationJson);
|
||||
})
|
||||
.flatMap(pluginList -> {
|
||||
if (params.containsKey(FieldName.DATASOURCE_LIST)) {
|
||||
return datasourceExportableService.getExportableEntities(
|
||||
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson);
|
||||
if (partialExportFileDTO.getDatasourceList().size() > 0) {
|
||||
return datasourceExportableService
|
||||
.getExportableEntities(
|
||||
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson)
|
||||
.thenReturn(applicationJson);
|
||||
}
|
||||
return Mono.just(applicationJson);
|
||||
})
|
||||
.flatMap(appJson -> {
|
||||
if (params.containsKey(FieldName.CUSTOM_JS_LIB_LIST)) {
|
||||
if (partialExportFileDTO.getCustomJsLib().size() > 0) {
|
||||
return exportFilteredCustomJSLib(
|
||||
applicationId,
|
||||
Set.copyOf(params.get(FieldName.CUSTOM_JS_LIB_LIST)),
|
||||
partialExportFileDTO.getCustomJsLib(),
|
||||
applicationJson,
|
||||
branchName)
|
||||
.flatMap(jsLibList -> {
|
||||
|
|
@ -129,33 +128,34 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
// update page name in meta and exportable DTO for resource to name mapping
|
||||
.flatMap(branchedPageId -> updatePageNameInResourceMapDTO(branchedPageId, mappedResourcesDTO))
|
||||
// export actions
|
||||
// export js objects
|
||||
.flatMap(branchedPageId -> {
|
||||
if (params.containsKey(FieldName.ACTION_LIST)
|
||||
|| params.containsKey(FieldName.ACTION_COLLECTION_LIST)) {
|
||||
return exportActions(
|
||||
if (partialExportFileDTO.getActionCollectionList().size() > 0) {
|
||||
return exportActionCollections(
|
||||
branchedPageId,
|
||||
Set.copyOf(params.get(FieldName.ACTION_LIST)),
|
||||
partialExportFileDTO.getActionCollectionList(),
|
||||
applicationJson,
|
||||
mappedResourcesDTO)
|
||||
.then(Mono.just(branchedPageId));
|
||||
}
|
||||
return Mono.just(branchedPageId);
|
||||
})
|
||||
// export js objects
|
||||
.flatMap(branchedPageId -> {
|
||||
if (params.containsKey(FieldName.ACTION_COLLECTION_LIST)) {
|
||||
return exportActionCollections(
|
||||
branchedPageId,
|
||||
Set.copyOf(params.get(FieldName.ACTION_COLLECTION_LIST)),
|
||||
applicationJson,
|
||||
mappedResourcesDTO);
|
||||
if (partialExportFileDTO.getActionCollectionList().size() > 0
|
||||
|| partialExportFileDTO.getActionList().size() > 0) {
|
||||
return exportActions(
|
||||
branchedPageId,
|
||||
partialExportFileDTO.getActionList(),
|
||||
applicationJson,
|
||||
mappedResourcesDTO)
|
||||
.then(Mono.just(branchedPageId));
|
||||
}
|
||||
return Mono.just(applicationJson);
|
||||
return Mono.just(branchedPageId);
|
||||
})
|
||||
.flatMap(appJson -> {
|
||||
// Remove the datasources not in use
|
||||
if (params.containsKey(FieldName.DATASOURCE_LIST)) {
|
||||
exportDatasource(Set.copyOf(params.get(FieldName.DATASOURCE_LIST)), applicationJson);
|
||||
if (partialExportFileDTO.getDatasourceList().size() > 0) {
|
||||
exportDatasource(partialExportFileDTO.getDatasourceList(), applicationJson);
|
||||
// Sanitise the datasource
|
||||
datasourceExportableService.sanitizeEntities(
|
||||
exportingMetaDTO,
|
||||
|
|
@ -168,7 +168,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
.map(exportedJson -> {
|
||||
String applicationName =
|
||||
applicationJson.getExportedApplication().getName();
|
||||
applicationJson.setWidgets(widgets);
|
||||
applicationJson.setWidgets(partialExportFileDTO.getWidget());
|
||||
applicationJson.setExportedApplication(null);
|
||||
String stringifiedFile = gson.toJson(exportedJson);
|
||||
Object jsonObject = gson.fromJson(stringifiedFile, Object.class);
|
||||
|
|
@ -186,7 +186,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
});
|
||||
}
|
||||
|
||||
private void exportDatasource(Set<String> validDatasource, ApplicationJson applicationJson) {
|
||||
private void exportDatasource(List<String> validDatasource, ApplicationJson applicationJson) {
|
||||
List<DatasourceStorage> datasourceList = applicationJson.getDatasourceList().stream()
|
||||
.filter(datasourceStorage -> validDatasource.contains(datasourceStorage.getDatasourceId()))
|
||||
.toList();
|
||||
|
|
@ -194,7 +194,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
}
|
||||
|
||||
private Mono<ApplicationJson> exportFilteredCustomJSLib(
|
||||
String applicationId, Set<String> customJSLibSet, ApplicationJson applicationJson, String branchName) {
|
||||
String applicationId, List<String> customJSLibSet, ApplicationJson applicationJson, String branchName) {
|
||||
return customJSLibService
|
||||
.getAllJSLibsInApplication(applicationId, branchName, false)
|
||||
.flatMap(customJSLibs -> {
|
||||
|
|
@ -209,7 +209,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
|
||||
private Mono<ApplicationJson> exportActions(
|
||||
String pageId,
|
||||
Set<String> validActions,
|
||||
List<String> validActions,
|
||||
ApplicationJson applicationJson,
|
||||
MappedExportableResourcesDTO mappedResourcesDTO) {
|
||||
return newActionService.findByPageId(pageId).collectList().flatMap(actions -> {
|
||||
|
|
@ -229,7 +229,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
|
|||
|
||||
private Mono<ApplicationJson> exportActionCollections(
|
||||
String pageId,
|
||||
Set<String> validActions,
|
||||
List<String> validActions,
|
||||
ApplicationJson applicationJson,
|
||||
MappedExportableResourcesDTO mappedResourcesDTO) {
|
||||
return actionCollectionService.findByPageId(pageId).collectList().flatMap(actionCollections -> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
package com.appsmith.server.imports.internal;
|
||||
|
||||
public interface PartialImportService extends PartialImportServiceCE {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.appsmith.server.imports.internal;
|
||||
|
||||
import com.appsmith.server.domains.Application;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface PartialImportServiceCE {
|
||||
|
||||
Mono<Application> importResourceInPage(
|
||||
String workspaceId, String applicationId, String pageId, String branchName, Part file);
|
||||
}
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
package com.appsmith.server.imports.internal;
|
||||
|
||||
import com.appsmith.external.constants.AnalyticsEvents;
|
||||
import com.appsmith.external.models.Datasource;
|
||||
import com.appsmith.server.acl.AclPermission;
|
||||
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.NewAction;
|
||||
import com.appsmith.server.domains.NewPage;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.domains.Workspace;
|
||||
import com.appsmith.server.dtos.ApplicationJson;
|
||||
import com.appsmith.server.dtos.ImportingMetaDTO;
|
||||
import com.appsmith.server.dtos.MappedImportableResourcesDTO;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import com.appsmith.server.helpers.ce.ImportApplicationPermissionProvider;
|
||||
import com.appsmith.server.imports.importable.ImportableService;
|
||||
import com.appsmith.server.newpages.base.NewPageService;
|
||||
import com.appsmith.server.repositories.PermissionGroupRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.ApplicationService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.appsmith.server.solutions.ActionPermission;
|
||||
import com.appsmith.server.solutions.ApplicationPermission;
|
||||
import com.appsmith.server.solutions.DatasourcePermission;
|
||||
import com.appsmith.server.solutions.PagePermission;
|
||||
import com.appsmith.server.solutions.WorkspacePermission;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
||||
|
||||
private final ImportApplicationService importApplicationService;
|
||||
private final WorkspaceService workspaceService;
|
||||
private final ApplicationService applicationService;
|
||||
private final AnalyticsService analyticsService;
|
||||
private final DatasourcePermission datasourcePermission;
|
||||
private final WorkspacePermission workspacePermission;
|
||||
private final ApplicationPermission applicationPermission;
|
||||
private final PagePermission pagePermission;
|
||||
private final ActionPermission actionPermission;
|
||||
private final Gson gson;
|
||||
private final TransactionalOperator transactionalOperator;
|
||||
private final PermissionGroupRepository permissionGroupRepository;
|
||||
private final ImportableService<Plugin> pluginImportableService;
|
||||
private final ImportableService<NewPage> newPageImportableService;
|
||||
private final ImportableService<CustomJSLib> customJSLibImportableService;
|
||||
private final ImportableService<Datasource> datasourceImportableService;
|
||||
private final ImportableService<NewAction> newActionImportableService;
|
||||
private final ImportableService<ActionCollection> actionCollectionImportableService;
|
||||
private final NewPageService newPageService;
|
||||
|
||||
@Override
|
||||
public Mono<Application> importResourceInPage(
|
||||
String workspaceId, String applicationId, String pageId, String branchName, Part file) {
|
||||
/*
|
||||
1. Get branchedPageId from pageId and branchName
|
||||
2. Get Application Mono
|
||||
3. Prepare the Meta DTO's
|
||||
4. Get plugin data
|
||||
5. Import datasources
|
||||
6. Import customJsLib
|
||||
7. Import actions
|
||||
8. Import actionCollection
|
||||
*/
|
||||
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO = new MappedImportableResourcesDTO();
|
||||
|
||||
Mono<String> branchedPageIdMono =
|
||||
newPageService.findBranchedPageId(branchName, pageId, AclPermission.MANAGE_PAGES);
|
||||
|
||||
// Extract file and get App Json
|
||||
Mono<Application> partiallyImportedAppMono = importApplicationService
|
||||
.extractApplicationJson(file)
|
||||
.zipWith(getImportApplicationPermissions())
|
||||
.flatMap(tuple -> {
|
||||
ApplicationJson applicationJson = tuple.getT1();
|
||||
ImportApplicationPermissionProvider permissionProvider = tuple.getT2();
|
||||
// Set Application in App JSON, remove the pages other than the one to be imported in
|
||||
// Set the current page in the JSON to be imported
|
||||
// Debug and get the value from getImportApplicationMono method if any difference
|
||||
// Modify the Application set in JSON to be imported
|
||||
|
||||
Mono<Workspace> workspaceMono = workspaceService
|
||||
.findById(workspaceId, permissionProvider.getRequiredPermissionOnTargetWorkspace())
|
||||
.switchIfEmpty(Mono.defer(() -> {
|
||||
log.error(
|
||||
"No workspace found with id: {} and permission: {}",
|
||||
workspaceId,
|
||||
permissionProvider.getRequiredPermissionOnTargetWorkspace());
|
||||
return Mono.error(new AppsmithException(
|
||||
AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId));
|
||||
}))
|
||||
.cache();
|
||||
|
||||
ImportingMetaDTO importingMetaDTO =
|
||||
new ImportingMetaDTO(workspaceId, applicationId, branchName, false, permissionProvider);
|
||||
|
||||
// Get the Application from DB
|
||||
Mono<Application> importedApplicationMono = applicationService
|
||||
.findByBranchNameAndDefaultApplicationId(
|
||||
branchName,
|
||||
applicationId,
|
||||
permissionProvider.getRequiredPermissionOnTargetApplication())
|
||||
.cache();
|
||||
|
||||
return importedApplicationMono
|
||||
.flatMap(application -> {
|
||||
applicationJson.setExportedApplication(application);
|
||||
return Mono.just(applicationJson);
|
||||
})
|
||||
// Import Custom Js Lib and Datasource
|
||||
.then(getApplicationImportableEntities(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson))
|
||||
.thenReturn("done")
|
||||
// Update the pageName map for actions and action collection
|
||||
.then(paneNameMapForActionAndActionCollectionInAppJson(
|
||||
branchedPageIdMono, applicationJson, mappedImportableResourcesDTO))
|
||||
.thenReturn("done")
|
||||
// Import Actions and action collection
|
||||
.then(getActionAndActionCollectionImport(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson))
|
||||
.thenReturn("done")
|
||||
.then(Mono.defer(() -> {
|
||||
Application application = applicationJson.getExportedApplication();
|
||||
return newActionImportableService
|
||||
.updateImportedEntities(
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO)
|
||||
.then(newPageImportableService.updateImportedEntities(
|
||||
application, importingMetaDTO, mappedImportableResourcesDTO))
|
||||
.flatMap(
|
||||
newPage -> applicationService.update(application.getId(), application));
|
||||
}));
|
||||
})
|
||||
.as(transactionalOperator::transactional);
|
||||
|
||||
// Send Analytics event
|
||||
return partiallyImportedAppMono.flatMap(application -> {
|
||||
final Map<String, Object> eventData = Map.of(FieldName.APPLICATION, application);
|
||||
|
||||
final Map<String, Object> data = Map.of(
|
||||
FieldName.APPLICATION_ID, application.getId(),
|
||||
FieldName.WORKSPACE_ID, application.getWorkspaceId(),
|
||||
FieldName.EVENT_DATA, eventData);
|
||||
|
||||
return analyticsService.sendObjectEvent(AnalyticsEvents.PARTIAL_IMPORT, application, data);
|
||||
});
|
||||
}
|
||||
|
||||
private Mono<ImportApplicationPermissionProvider> getImportApplicationPermissions() {
|
||||
return permissionGroupRepository.getCurrentUserPermissionGroups().flatMap(userPermissionGroups -> {
|
||||
ImportApplicationPermissionProvider permissionProvider = ImportApplicationPermissionProvider.builder(
|
||||
applicationPermission,
|
||||
pagePermission,
|
||||
actionPermission,
|
||||
datasourcePermission,
|
||||
workspacePermission)
|
||||
.requiredPermissionOnTargetWorkspace(workspacePermission.getReadPermission())
|
||||
.requiredPermissionOnTargetApplication(applicationPermission.getEditPermission())
|
||||
.permissionRequiredToCreateDatasource(true)
|
||||
.permissionRequiredToEditDatasource(true)
|
||||
.currentUserPermissionGroups(userPermissionGroups)
|
||||
.build();
|
||||
return Mono.just(permissionProvider);
|
||||
});
|
||||
}
|
||||
|
||||
private Mono<Void> getApplicationImportableEntities(
|
||||
ImportingMetaDTO importingMetaDTO,
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> importedApplicationMono,
|
||||
ApplicationJson applicationJson) {
|
||||
Mono<Void> customJSLibMono = pluginImportableService.importEntities(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson);
|
||||
|
||||
Mono<Void> datasourceMono = datasourceImportableService.importEntities(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson);
|
||||
|
||||
Mono<Void> customJsLibMono = customJSLibImportableService.importEntities(
|
||||
importingMetaDTO, mappedImportableResourcesDTO, null, null, applicationJson);
|
||||
|
||||
return Flux.merge(List.of(customJsLibMono, datasourceMono, customJSLibMono))
|
||||
.then();
|
||||
}
|
||||
|
||||
private Mono<Void> getActionAndActionCollectionImport(
|
||||
ImportingMetaDTO importingMetaDTO,
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO,
|
||||
Mono<Workspace> workspaceMono,
|
||||
Mono<Application> importedApplicationMono,
|
||||
ApplicationJson applicationJson) {
|
||||
Mono<Void> actionMono = newActionImportableService.importEntities(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson);
|
||||
|
||||
Mono<Void> actionCollectionMono = actionCollectionImportableService.importEntities(
|
||||
importingMetaDTO,
|
||||
mappedImportableResourcesDTO,
|
||||
workspaceMono,
|
||||
importedApplicationMono,
|
||||
applicationJson);
|
||||
|
||||
return Flux.merge(List.of(actionMono, actionCollectionMono)).then();
|
||||
}
|
||||
|
||||
private Mono<String> paneNameMapForActionAndActionCollectionInAppJson(
|
||||
Mono<String> branchedPageIdMono,
|
||||
ApplicationJson applicationJson,
|
||||
MappedImportableResourcesDTO mappedImportableResourcesDTO) {
|
||||
return branchedPageIdMono.flatMap(
|
||||
pageId -> newPageService.findById(pageId, Optional.empty()).flatMap(newPage -> {
|
||||
String pageName = newPage.getUnpublishedPage().getName();
|
||||
// update page name reference with newPage
|
||||
Map<String, NewPage> pageNameMap = new HashMap<>();
|
||||
pageNameMap.put(pageName, newPage);
|
||||
mappedImportableResourcesDTO.setPageNameMap(pageNameMap);
|
||||
|
||||
applicationJson.getActionList().forEach(action -> {
|
||||
action.getPublishedAction().setPageId(pageName);
|
||||
action.getUnpublishedAction().setPageId(pageName);
|
||||
if (action.getPublishedAction().getCollectionId() != null) {
|
||||
String collectionName = action.getPublishedAction()
|
||||
.getCollectionId()
|
||||
.split("_")[1];
|
||||
action.getPublishedAction().setCollectionId(pageName + "_" + collectionName);
|
||||
action.getUnpublishedAction().setCollectionId(pageName + "_" + collectionName);
|
||||
}
|
||||
|
||||
String actionName = action.getId().split("_")[1];
|
||||
action.setId(pageName + "_" + actionName);
|
||||
action.setGitSyncId(null);
|
||||
});
|
||||
|
||||
applicationJson.getActionCollectionList().forEach(actionCollection -> {
|
||||
actionCollection.getPublishedCollection().setPageId(pageName);
|
||||
actionCollection.getUnpublishedCollection().setPageId(pageName);
|
||||
|
||||
String collectionName = actionCollection.getId().split("_")[1];
|
||||
actionCollection.setId(pageName + "_" + collectionName);
|
||||
actionCollection.setGitSyncId(null);
|
||||
});
|
||||
return Mono.just(pageName);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.appsmith.server.imports.internal;
|
||||
|
||||
import com.appsmith.external.models.Datasource;
|
||||
import com.appsmith.server.domains.ActionCollection;
|
||||
import com.appsmith.server.domains.CustomJSLib;
|
||||
import com.appsmith.server.domains.NewAction;
|
||||
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.repositories.PermissionGroupRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.ApplicationService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.appsmith.server.solutions.ActionPermission;
|
||||
import com.appsmith.server.solutions.ApplicationPermission;
|
||||
import com.appsmith.server.solutions.DatasourcePermission;
|
||||
import com.appsmith.server.solutions.PagePermission;
|
||||
import com.appsmith.server.solutions.WorkspacePermission;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Primary
|
||||
public class PartialImportServiceImpl extends PartialImportServiceCEImpl implements PartialImportService {
|
||||
|
||||
public PartialImportServiceImpl(
|
||||
ImportApplicationService importApplicationService,
|
||||
WorkspaceService workspaceService,
|
||||
ApplicationService applicationService,
|
||||
AnalyticsService analyticsService,
|
||||
DatasourcePermission datasourcePermission,
|
||||
WorkspacePermission workspacePermission,
|
||||
ApplicationPermission applicationPermission,
|
||||
PagePermission pagePermission,
|
||||
ActionPermission actionPermission,
|
||||
Gson gson,
|
||||
TransactionalOperator transactionalOperator,
|
||||
PermissionGroupRepository permissionGroupRepository,
|
||||
ImportableService<Plugin> pluginImportableService,
|
||||
ImportableService<NewPage> newPageImportableService,
|
||||
ImportableService<CustomJSLib> customJSLibImportableService,
|
||||
ImportableService<Datasource> datasourceImportableService,
|
||||
ImportableService<NewAction> newActionImportableService,
|
||||
ImportableService<ActionCollection> actionCollectionImportableService,
|
||||
NewPageService newPageService) {
|
||||
super(
|
||||
importApplicationService,
|
||||
workspaceService,
|
||||
applicationService,
|
||||
analyticsService,
|
||||
datasourcePermission,
|
||||
workspacePermission,
|
||||
applicationPermission,
|
||||
pagePermission,
|
||||
actionPermission,
|
||||
gson,
|
||||
transactionalOperator,
|
||||
permissionGroupRepository,
|
||||
pluginImportableService,
|
||||
newPageImportableService,
|
||||
customJSLibImportableService,
|
||||
datasourceImportableService,
|
||||
newActionImportableService,
|
||||
actionCollectionImportableService,
|
||||
newPageService);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import com.appsmith.server.fork.internal.ApplicationForkingService;
|
|||
import com.appsmith.server.helpers.GitFileUtils;
|
||||
import com.appsmith.server.helpers.RedisUtils;
|
||||
import com.appsmith.server.imports.internal.ImportApplicationService;
|
||||
import com.appsmith.server.imports.internal.PartialImportService;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.ApplicationPageService;
|
||||
import com.appsmith.server.services.ApplicationService;
|
||||
|
|
@ -83,6 +84,9 @@ public class ApplicationControllerTest {
|
|||
@MockBean
|
||||
PartialExportService partialExportService;
|
||||
|
||||
@MockBean
|
||||
PartialImportService partialImportService;
|
||||
|
||||
private String getFileName(int length) {
|
||||
StringBuilder fileName = new StringBuilder();
|
||||
for (int count = 0; count < length; count++) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user