fix: Forking with JS collections (#8799)

This commit is contained in:
Nidhi 2021-10-26 11:04:04 +05:30 committed by GitHub
parent 7016d9f6d0
commit 295f8b9631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 244 additions and 173 deletions

View File

@ -16,4 +16,6 @@ public interface CustomActionCollectionRepository extends AppsmithRepository<Act
Flux<ActionCollection> findAllActionCollectionsByNameAndPageIdsAndViewMode(String name, List<String> pageIds, boolean viewMode, AclPermission aclPermission, Sort sort); Flux<ActionCollection> findAllActionCollectionsByNameAndPageIdsAndViewMode(String name, List<String> pageIds, boolean viewMode, AclPermission aclPermission, Sort sort);
Flux<ActionCollection> findByPageId(String pageId, AclPermission permission); Flux<ActionCollection> findByPageId(String pageId, AclPermission permission);
Flux<ActionCollection> findByPageId(String pageId);
} }

View File

@ -122,4 +122,9 @@ public class CustomActionCollectionRepositoryImpl extends BaseAppsmithRepository
}); });
} }
@Override
public Flux<ActionCollection> findByPageId(String pageId) {
return this.findByPageId(pageId, null);
}
} }

View File

@ -40,7 +40,7 @@ public interface ActionCollectionService extends CrudService<ActionCollection, S
Mono<ActionCollectionDTO> findActionCollectionDTObyIdAndViewMode(String id, Boolean viewMode, AclPermission permission); Mono<ActionCollectionDTO> findActionCollectionDTObyIdAndViewMode(String id, Boolean viewMode, AclPermission permission);
Flux<ActionCollection> findByPageId(String pageId, AclPermission permission);
Flux<ActionCollectionViewDTO> getActionCollectionsForViewMode(String applicationId); Flux<ActionCollectionViewDTO> getActionCollectionsForViewMode(String applicationId);
Flux<ActionCollection> findByPageId(String pageId);
} }

View File

@ -303,8 +303,8 @@ public class ActionCollectionServiceImpl extends BaseService<ActionCollectionRep
} }
@Override @Override
public Flux<ActionCollection> findByPageId(String pageId, AclPermission permission) { public Flux<ActionCollection> findByPageId(String pageId) {
return repository.findByPageId(pageId, permission); return repository.findByPageId(pageId);
} }
@Override @Override

View File

@ -593,7 +593,7 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
/** /**
* Only delete unpublished action collection and not the entire action collection. * Only delete unpublished action collection and not the entire action collection.
*/ */
Mono<List<ActionCollectionDTO>> archivedActionCollectionsMono = actionCollectionService.findByPageId(page.getId(), MANAGE_ACTIONS) Mono<List<ActionCollectionDTO>> archivedActionCollectionsMono = actionCollectionService.findByPageId(page.getId())
.flatMap(actionCollection -> { .flatMap(actionCollection -> {
log.debug("Going to archive actionCollectionId: {} for applicationId: {}", actionCollection.getId(), id); log.debug("Going to archive actionCollectionId: {} for applicationId: {}", actionCollection.getId(), id);
return actionCollectionService.deleteUnpublishedActionCollection(actionCollection.getId()); return actionCollectionService.deleteUnpublishedActionCollection(actionCollection.getId());

View File

@ -4,14 +4,15 @@ import com.appsmith.external.helpers.AppsmithEventContext;
import com.appsmith.external.helpers.AppsmithEventContextType; import com.appsmith.external.helpers.AppsmithEventContextType;
import com.appsmith.external.models.AuthenticationDTO; import com.appsmith.external.models.AuthenticationDTO;
import com.appsmith.external.models.BaseDomain; import com.appsmith.external.models.BaseDomain;
import com.appsmith.external.models.Datasource;
import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.ApplicationPage; import com.appsmith.server.domains.ApplicationPage;
import com.appsmith.external.models.Datasource;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.User; import com.appsmith.server.domains.User;
import com.appsmith.server.dtos.ActionCollectionDTO;
import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.dtos.ActionDTO;
import com.appsmith.server.dtos.DslActionDTO; import com.appsmith.server.dtos.DslActionDTO;
import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.dtos.PageDTO;
@ -20,11 +21,13 @@ import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.DatasourceRepository; import com.appsmith.server.repositories.DatasourceRepository;
import com.appsmith.server.repositories.NewPageRepository; import com.appsmith.server.repositories.NewPageRepository;
import com.appsmith.server.repositories.OrganizationRepository; import com.appsmith.server.repositories.OrganizationRepository;
import com.appsmith.server.services.ActionCollectionService;
import com.appsmith.server.services.ApplicationPageService; import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.ApplicationService; import com.appsmith.server.services.ApplicationService;
import com.appsmith.server.services.ConfigService; import com.appsmith.server.services.ConfigService;
import com.appsmith.server.services.DatasourceService; import com.appsmith.server.services.DatasourceService;
import com.appsmith.server.services.LayoutActionService; import com.appsmith.server.services.LayoutActionService;
import com.appsmith.server.services.LayoutCollectionService;
import com.appsmith.server.services.NewActionService; import com.appsmith.server.services.NewActionService;
import com.appsmith.server.services.OrganizationService; import com.appsmith.server.services.OrganizationService;
import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.SessionUserService;
@ -38,7 +41,6 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -64,6 +66,8 @@ public class ExamplesOrganizationCloner {
private final NewPageRepository newPageRepository; private final NewPageRepository newPageRepository;
private final NewActionService newActionService; private final NewActionService newActionService;
private final LayoutActionService layoutActionService; private final LayoutActionService layoutActionService;
private final ActionCollectionService actionCollectionService;
private final LayoutCollectionService layoutCollectionService;
public Mono<Organization> cloneExamplesOrganization() { public Mono<Organization> cloneExamplesOrganization() {
return sessionUserService return sessionUserService
@ -223,7 +227,7 @@ public class ExamplesOrganizationCloner {
? applicationPageService.makePageDefault(savedPage).thenReturn(savedPage) ? applicationPageService.makePageDefault(savedPage).thenReturn(savedPage)
: Mono.just(savedPage)) : Mono.just(savedPage))
.flatMap(savedPage -> newPageRepository.findById(savedPage.getId())) .flatMap(savedPage -> newPageRepository.findById(savedPage.getId()))
.flatMapMany(savedPage -> { .flatMap(savedPage -> {
clonedPages.add(savedPage); clonedPages.add(savedPage);
return newActionService return newActionService
.findByPageId(templatePageId) .findByPageId(templatePageId)
@ -232,45 +236,83 @@ public class ExamplesOrganizationCloner {
log.info("Preparing action for cloning {} {}.", action.getName(), newAction.getId()); log.info("Preparing action for cloning {} {}.", action.getName(), newAction.getId());
action.setPageId(savedPage.getId()); action.setPageId(savedPage.getId());
return newAction; return newAction;
})
.flatMap(newAction -> {
final String originalActionId = newAction.getId();
log.info("Creating clone of action {}", originalActionId);
makePristine(newAction);
newAction.setOrganizationId(toOrganizationId);
ActionDTO action = newAction.getUnpublishedAction();
final String originalCollectionId = action.getCollectionId();
action.setCollectionId(null);
Mono<ActionDTO> actionMono = Mono.just(action);
final Datasource datasourceInsideAction = action.getDatasource();
if (datasourceInsideAction != null) {
if (datasourceInsideAction.getId() != null) {
final String datasourceId = datasourceInsideAction.getId();
if (!cloneDatasourceMonos.containsKey(datasourceId)) {
cloneDatasourceMonos.put(datasourceId, cloneDatasource(datasourceId, toOrganizationId).cache());
}
actionMono = cloneDatasourceMonos.get(datasourceId)
.map(newDatasource -> {
action.setDatasource(newDatasource);
return action;
});
} else {
datasourceInsideAction.setOrganizationId(toOrganizationId);
}
}
return Mono.zip(actionMono
.flatMap(actionDTO -> layoutActionService.createAction(
actionDTO, new AppsmithEventContext(AppsmithEventContextType.CLONE_PAGE))
)
.map(ActionDTO::getId),
Mono.justOrEmpty(originalActionId));
})
// This call to `collectMap` will wait for all actions in all pages to have been processed, and so the
// `clonedPages` list will also contain all pages cloned.
.collect(HashMap<String, String>::new, (map, tuple3) -> map.put(tuple3.getT2(), tuple3.getT1()))
.flatMap(actionIdsMap -> {
// Pick all action collections
return actionCollectionService
.findByPageId(templatePageId)
.flatMap(actionCollection -> {
// Keep a record of the original collection id
final String originalCollectionId = actionCollection.getId();
log.info("Creating clone of action collection {}", originalCollectionId);
// Sanitize them
makePristine(actionCollection);
final ActionCollectionDTO unpublishedCollection = actionCollection.getUnpublishedCollection();
unpublishedCollection.setPageId(savedPage.getId());
actionCollection.setOrganizationId(toOrganizationId);
actionCollection.setApplicationId(savedPage.getApplicationId());
actionCollectionService.generateAndSetPolicies(savedPage, actionCollection);
// Replace all action Ids from map
final HashSet<String> newActionIds = new HashSet<>();
unpublishedCollection
.getActionIds()
.stream()
.forEach(oldActionId -> newActionIds.add(actionIdsMap.get(oldActionId)));
unpublishedCollection.setActionIds(newActionIds);
return actionCollectionService.create(actionCollection)
.flatMap(newlyCreatedActionCollection -> {
return Flux.fromIterable(newActionIds)
.flatMap(newActionService::findById)
.flatMap(newlyCreatedAction -> {
newlyCreatedAction.getUnpublishedAction().setCollectionId(newlyCreatedAction.getId());
return newActionService.update(newlyCreatedAction.getId(), newlyCreatedAction);
})
.collectList();
});
})
.collectList()
.thenReturn(actionIdsMap);
}); });
}); });
}) })
.flatMap(newAction -> { .flatMap(actionIdsMap -> updateActionIdsInClonedPages(clonedPages, actionIdsMap))
final String originalActionId = newAction.getId();
log.info("Creating clone of action {}", originalActionId);
makePristine(newAction);
newAction.setOrganizationId(toOrganizationId);
ActionDTO action = newAction.getUnpublishedAction();
action.setCollectionId(null);
Mono<ActionDTO> actionMono = Mono.just(action);
final Datasource datasourceInsideAction = action.getDatasource();
if (datasourceInsideAction != null) {
if (datasourceInsideAction.getId() != null) {
final String datasourceId = datasourceInsideAction.getId();
if (!cloneDatasourceMonos.containsKey(datasourceId)) {
cloneDatasourceMonos.put(datasourceId, cloneDatasource(datasourceId, toOrganizationId).cache());
}
actionMono = cloneDatasourceMonos.get(datasourceId)
.map(newDatasource -> {
action.setDatasource(newDatasource);
return action;
});
} else {
datasourceInsideAction.setOrganizationId(toOrganizationId);
}
}
return actionMono
.flatMap(actionDTO -> layoutActionService.createAction(
actionDTO, new AppsmithEventContext(AppsmithEventContextType.CLONE_PAGE))
)
.map(ActionDTO::getId)
.zipWith(Mono.justOrEmpty(originalActionId));
})
// This call to `collectMap` will wait for all actions in all pages to have been processed, and so the
// `clonedPages` list will also contain all pages cloned.
.collectMap(Tuple2::getT2, Tuple2::getT1)
.flatMapMany(actionIdsMap -> updateActionIdsInClonedPages(clonedPages, actionIdsMap))
// Now publish all the example applications which have been cloned to ensure that there is a // Now publish all the example applications which have been cloned to ensure that there is a
// view mode for the newly created user. // view mode for the newly created user.
.then(Mono.just(newApplicationIds)) .then(Mono.just(newApplicationIds))

View File

@ -4,6 +4,7 @@ import com.appsmith.external.models.ActionConfiguration;
import com.appsmith.external.models.AuthenticationResponse; import com.appsmith.external.models.AuthenticationResponse;
import com.appsmith.external.models.Connection; import com.appsmith.external.models.Connection;
import com.appsmith.external.models.DBAuth; import com.appsmith.external.models.DBAuth;
import com.appsmith.external.models.Datasource;
import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.Endpoint; import com.appsmith.external.models.Endpoint;
import com.appsmith.external.models.OAuth2; import com.appsmith.external.models.OAuth2;
@ -11,15 +12,18 @@ import com.appsmith.external.models.PEMCertificate;
import com.appsmith.external.models.Property; import com.appsmith.external.models.Property;
import com.appsmith.external.models.SSLDetails; import com.appsmith.external.models.SSLDetails;
import com.appsmith.external.models.UploadedFile; import com.appsmith.external.models.UploadedFile;
import com.appsmith.external.plugins.PluginExecutor;
import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.ApplicationPage; import com.appsmith.server.domains.ApplicationPage;
import com.appsmith.external.models.Datasource;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewAction;
import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.PluginType;
import com.appsmith.server.domains.User;
import com.appsmith.server.dtos.ActionCollectionDTO;
import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.dtos.ActionDTO;
import com.appsmith.server.dtos.DslActionDTO; import com.appsmith.server.dtos.DslActionDTO;
import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.dtos.PageDTO;
@ -33,6 +37,7 @@ import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.ApplicationService; import com.appsmith.server.services.ApplicationService;
import com.appsmith.server.services.DatasourceService; import com.appsmith.server.services.DatasourceService;
import com.appsmith.server.services.LayoutActionService; import com.appsmith.server.services.LayoutActionService;
import com.appsmith.server.services.LayoutCollectionService;
import com.appsmith.server.services.NewActionService; import com.appsmith.server.services.NewActionService;
import com.appsmith.server.services.NewPageService; import com.appsmith.server.services.NewPageService;
import com.appsmith.server.services.OrganizationService; import com.appsmith.server.services.OrganizationService;
@ -111,6 +116,9 @@ public class ExamplesOrganizationClonerTests {
@MockBean @MockBean
private PluginExecutorHelper pluginExecutorHelper; private PluginExecutorHelper pluginExecutorHelper;
@MockBean
PluginExecutor pluginExecutor;
@Autowired @Autowired
private LayoutActionService layoutActionService; private LayoutActionService layoutActionService;
@ -128,11 +136,15 @@ public class ExamplesOrganizationClonerTests {
private Plugin installedPlugin; private Plugin installedPlugin;
@Autowired
private LayoutCollectionService layoutCollectionService;
private static class OrganizationData { private static class OrganizationData {
Organization organization; Organization organization;
List<Application> applications = new ArrayList<>(); List<Application> applications = new ArrayList<>();
List<Datasource> datasources = new ArrayList<>(); List<Datasource> datasources = new ArrayList<>();
List<ActionDTO> actions = new ArrayList<>(); List<ActionDTO> actions = new ArrayList<>();
List<ActionCollectionDTO> actionCollections = new ArrayList<>();
} }
public Mono<OrganizationData> loadOrganizationData(Organization organization) { public Mono<OrganizationData> loadOrganizationData(Organization organization) {
@ -148,7 +160,9 @@ public class ExamplesOrganizationClonerTests {
.findAllByOrganizationId(organization.getId(), READ_DATASOURCES) .findAllByOrganizationId(organization.getId(), READ_DATASOURCES)
.map(data.datasources::add), .map(data.datasources::add),
getActionsInOrganization(organization) getActionsInOrganization(organization)
.map(data.actions::add) .map(data.actions::add),
getActionCollectionsInOrganization(organization)
.map(data.actionCollections::add)
) )
.thenReturn(data); .thenReturn(data);
} }
@ -180,6 +194,7 @@ public class ExamplesOrganizationClonerTests {
assertThat(data.applications).isEmpty(); assertThat(data.applications).isEmpty();
assertThat(data.datasources).isEmpty(); assertThat(data.datasources).isEmpty();
assertThat(data.actions).isEmpty(); assertThat(data.actions).isEmpty();
assertThat(data.actionCollections).isEmpty();
}) })
.verifyComplete(); .verifyComplete();
} }
@ -233,6 +248,7 @@ public class ExamplesOrganizationClonerTests {
assertThat(data.datasources).isEmpty(); assertThat(data.datasources).isEmpty();
assertThat(data.actions).isEmpty(); assertThat(data.actions).isEmpty();
assertThat(data.actionCollections).isEmpty();
}) })
.verifyComplete(); .verifyComplete();
} }
@ -303,6 +319,7 @@ public class ExamplesOrganizationClonerTests {
assertThat(data.datasources).isEmpty(); assertThat(data.datasources).isEmpty();
assertThat(data.actions).isEmpty(); assertThat(data.actions).isEmpty();
assertThat(data.actionCollections).isEmpty();
}) })
.verifyComplete(); .verifyComplete();
} }
@ -345,6 +362,7 @@ public class ExamplesOrganizationClonerTests {
assertThat(data.applications).isEmpty(); assertThat(data.applications).isEmpty();
assertThat(data.datasources).isEmpty(); assertThat(data.datasources).isEmpty();
assertThat(data.actions).isEmpty(); assertThat(data.actions).isEmpty();
assertThat(data.actionCollections).isEmpty();
}) })
.verifyComplete(); .verifyComplete();
} }
@ -453,6 +471,7 @@ public class ExamplesOrganizationClonerTests {
assertThat(data.datasources).isEmpty(); assertThat(data.datasources).isEmpty();
assertThat(data.applications).isEmpty(); assertThat(data.applications).isEmpty();
assertThat(data.actions).isEmpty(); assertThat(data.actions).isEmpty();
assertThat(data.actionCollections).isEmpty();
}) })
.verifyComplete(); .verifyComplete();
} }
@ -514,6 +533,7 @@ public class ExamplesOrganizationClonerTests {
assertThat(data.applications).isEmpty(); assertThat(data.applications).isEmpty();
assertThat(data.actions).isEmpty(); assertThat(data.actions).isEmpty();
assertThat(data.actionCollections).isEmpty();
}) })
.verifyComplete(); .verifyComplete();
} }
@ -582,144 +602,136 @@ public class ExamplesOrganizationClonerTests {
assertThat(data.datasources).isEmpty(); assertThat(data.datasources).isEmpty();
assertThat(data.actions).isEmpty(); assertThat(data.actions).isEmpty();
assertThat(data.actionCollections).isEmpty();
}) })
.verifyComplete(); .verifyComplete();
} }
@Test @Test
@WithUserDetails(value = "api_user") @WithUserDetails(value = "api_user")
public void cloneOrganizationWithDatasourcesAndApplicationsAndActions() { public void cloneOrganizationWithDatasourcesAndApplicationsAndActionsAndCollections() {
Organization newOrganization = new Organization(); Organization newOrganization = new Organization();
newOrganization.setName("Template Organization 2"); newOrganization.setName("Template Organization 2");
final Mono<OrganizationData> resultMono = Mono final Organization organization = organizationService.create(newOrganization).block();
.zip( final User user = sessionUserService.getCurrentUser().block();
organizationService.create(newOrganization),
sessionUserService.getCurrentUser()
)
.flatMap(tuple -> {
final Organization organization = tuple.getT1();
final Application app1 = new Application(); final Application app1 = new Application();
app1.setName("first application"); app1.setName("first application");
app1.setOrganizationId(organization.getId()); app1.setOrganizationId(organization.getId());
app1.setIsPublic(true); app1.setIsPublic(true);
final Application app2 = new Application(); final Application app2 = new Application();
app2.setName("second application"); app2.setName("second application");
app2.setOrganizationId(organization.getId()); app2.setOrganizationId(organization.getId());
app2.setIsPublic(true); app2.setIsPublic(true);
final Datasource ds1 = new Datasource(); final Datasource ds1 = new Datasource();
ds1.setName("datasource 1"); ds1.setName("datasource 1");
ds1.setOrganizationId(organization.getId()); ds1.setOrganizationId(organization.getId());
ds1.setPluginId(installedPlugin.getId()); ds1.setPluginId(installedPlugin.getId());
final Datasource ds2 = new Datasource(); final Datasource ds2 = new Datasource();
ds2.setName("datasource 2"); ds2.setName("datasource 2");
ds2.setOrganizationId(organization.getId()); ds2.setOrganizationId(organization.getId());
ds2.setPluginId(installedPlugin.getId()); ds2.setPluginId(installedPlugin.getId());
return Mono final Application app = applicationPageService.createApplication(app1).block();
.zip( final Application app2Again = applicationPageService.createApplication(app2).block();
applicationPageService.createApplication(app1), final Datasource ds1WithId = datasourceService.create(ds1).block();
applicationPageService.createApplication(app2), final Datasource ds2WithId = datasourceService.create(ds2).block();
datasourceService.create(ds1),
datasourceService.create(ds2)
)
.flatMap(tuple1 -> {
final Application app = tuple1.getT1();
final String pageId1 = app.getPages().get(0).getId();
final Datasource ds1WithId = tuple1.getT3();
final PageDTO newPage = new PageDTO(); final String pageId1 = app.getPages().get(0).getId();
newPage.setName("A New Page");
newPage.setApplicationId(app.getId());
newPage.setLayouts(new ArrayList<>());
final Layout layout = new Layout();
layout.setId(new ObjectId().toString());
JSONObject dsl = new JSONObject();
dsl.put("widgetName", "testWidget");
JSONArray temp = new JSONArray();
temp.addAll(List.of(new JSONObject(Map.of("key", "testField"))));
dsl.put("dynamicBindingPathList", temp);
dsl.put("testField", "draft {{ newPageAction.data }}");
layout.setDsl(dsl);
JSONObject publishedDsl = new JSONObject(dsl);
publishedDsl.put("testField", "published {{ newPageAction.data }}");
layout.setPublishedDsl(publishedDsl);
final DslActionDTO actionDTO = new DslActionDTO();
final HashSet<DslActionDTO> dslActionDTOS = new HashSet<>(List.of(actionDTO));
layout.setLayoutOnLoadActions(List.of(dslActionDTOS));
newPage.getLayouts().add(layout);
final ActionDTO newPageAction = new ActionDTO(); final PageDTO newPage = new PageDTO();
newPageAction.setName("newPageAction"); newPage.setName("A New Page");
newPageAction.setOrganizationId(organization.getId()); newPage.setApplicationId(app.getId());
newPageAction.setDatasource(ds1WithId); newPage.setLayouts(new ArrayList<>());
newPageAction.setPluginId(installedPlugin.getId()); final Layout layout = new Layout();
newPageAction.setActionConfiguration(new ActionConfiguration()); layout.setId(new ObjectId().toString());
newPageAction.getActionConfiguration().setHttpMethod(HttpMethod.GET); JSONObject dsl = new JSONObject();
dsl.put("widgetName", "testWidget");
JSONArray temp = new JSONArray();
temp.addAll(List.of(new JSONObject(Map.of("key", "testField"))));
dsl.put("dynamicBindingPathList", temp);
dsl.put("testField", "draft {{ newPageAction.data }}");
layout.setDsl(dsl);
JSONObject publishedDsl = new JSONObject(dsl);
publishedDsl.put("testField", "published {{ newPageAction.data }}");
layout.setPublishedDsl(publishedDsl);
final DslActionDTO actionDTO = new DslActionDTO();
final HashSet<DslActionDTO> dslActionDTOS = new HashSet<>(List.of(actionDTO));
layout.setLayoutOnLoadActions(List.of(dslActionDTOS));
newPage.getLayouts().add(layout);
final ActionDTO action1 = new ActionDTO(); final ActionDTO newPageAction = new ActionDTO();
action1.setName("action1"); newPageAction.setName("newPageAction");
action1.setPageId(pageId1); newPageAction.setOrganizationId(organization.getId());
action1.setOrganizationId(organization.getId()); newPageAction.setDatasource(ds1WithId);
action1.setDatasource(ds1WithId); newPageAction.setPluginId(installedPlugin.getId());
action1.setPluginId(installedPlugin.getId()); newPageAction.setActionConfiguration(new ActionConfiguration());
newPageAction.getActionConfiguration().setHttpMethod(HttpMethod.GET);
final ActionDTO action2 = new ActionDTO(); final ActionDTO action1 = new ActionDTO();
action2.setPageId(pageId1); action1.setName("action1");
action2.setName("action2"); action1.setPageId(pageId1);
action2.setOrganizationId(organization.getId()); action1.setOrganizationId(organization.getId());
action2.setDatasource(ds1WithId); action1.setDatasource(ds1WithId);
action2.setPluginId(installedPlugin.getId()); action1.setPluginId(installedPlugin.getId());
final Application app2Again = tuple1.getT2(); final String pageId2 = app2Again.getPages().get(0).getId();
final String pageId2 = app2Again.getPages().get(0).getId();
final Datasource ds2WithId = tuple1.getT4();
final ActionDTO action3 = new ActionDTO(); final ActionDTO action3 = new ActionDTO();
action3.setName("action3"); action3.setName("action3");
action3.setPageId(pageId2); action3.setPageId(pageId2);
action3.setOrganizationId(organization.getId()); action3.setOrganizationId(organization.getId());
action3.setDatasource(ds2WithId); action3.setDatasource(ds2WithId);
action3.setPluginId(installedPlugin.getId()); action3.setPluginId(installedPlugin.getId());
final ActionDTO action4 = new ActionDTO(); Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any())).thenReturn(Mono.just(pluginExecutor));
action4.setPageId(pageId2); Mockito.when(pluginExecutor.getHintMessages(Mockito.any(), Mockito.any()))
action4.setName("action4"); .thenReturn(Mono.zip(Mono.just(new HashSet<>()), Mono.just(new HashSet<>())));
action4.setOrganizationId(organization.getId());
action4.setDatasource(ds2WithId);
action4.setPluginId(installedPlugin.getId());
return Mono.when( Datasource jsDatasource = new Datasource();
applicationPageService.createPage(newPage) jsDatasource.setName("Default Database");
.flatMap(page -> { jsDatasource.setOrganizationId(organization.getId());
newPageAction.setPageId(page.getId()); Plugin installedJsPlugin = pluginRepository.findByPackageName("installed-js-plugin").block();
return applicationPageService.addPageToApplication(app, page, false) assert installedJsPlugin != null;
.then(layoutActionService.createSingleAction(newPageAction)) jsDatasource.setPluginId(installedJsPlugin.getId());
.flatMap(savedAction -> layoutActionService.updateSingleAction(savedAction.getId(), savedAction))
.then(newPageService.findPageById(page.getId(), READ_PAGES, false)); ActionCollectionDTO actionCollectionDTO1 = new ActionCollectionDTO();
}) actionCollectionDTO1.setName("testCollection1");
.map(tuple2 -> { actionCollectionDTO1.setPageId(app.getPages().get(0).getId());
log.info("Created action and added page to app {}", tuple2); actionCollectionDTO1.setApplicationId(app.getId());
return tuple2; actionCollectionDTO1.setOrganizationId(organization.getId());
}), actionCollectionDTO1.setPluginId(jsDatasource.getPluginId());
layoutActionService.createSingleAction(action1), ActionDTO action5 = new ActionDTO();
layoutActionService.createSingleAction(action2), action5.setName("run");
layoutActionService.createSingleAction(action3), action5.setActionConfiguration(new ActionConfiguration());
layoutActionService.createSingleAction(action4) action5.getActionConfiguration().setBody("mockBody");
).thenReturn(List.of(tuple1.getT1(), tuple1.getT2())); actionCollectionDTO1.setActions(List.of(action5));
}) actionCollectionDTO1.setPluginType(PluginType.JS);
.flatMap(applications ->
examplesOrganizationCloner.cloneOrganizationForUser( applicationPageService.createPage(newPage)
organization.getId(), .flatMap(page -> {
tuple.getT2(), newPageAction.setPageId(page.getId());
Flux.fromIterable(applications), return applicationPageService.addPageToApplication(app, page, false)
Flux.empty() .then(layoutActionService.createSingleAction(newPageAction))
) .flatMap(savedAction -> layoutActionService.updateSingleAction(savedAction.getId(), savedAction))
); .then(newPageService.findPageById(page.getId(), READ_PAGES, false));
}) })
.map(tuple2 -> {
log.info("Created action and added page to app {}", tuple2);
return tuple2;
}).block();
layoutActionService.createSingleAction(action1).block();
layoutActionService.createSingleAction(action3).block();
layoutCollectionService.createCollection(actionCollectionDTO1).block();
final Mono<OrganizationData> resultMono = examplesOrganizationCloner.cloneOrganizationForUser(
organization.getId(),
user,
Flux.fromIterable(List.of(app, app2Again)),
Flux.empty())
.doOnError(error -> log.error("Error preparing data for test", error)) .doOnError(error -> log.error("Error preparing data for test", error))
.flatMap(this::loadOrganizationData); .flatMap(this::loadOrganizationData);
@ -736,16 +748,15 @@ public class ExamplesOrganizationClonerTests {
"second application" "second application"
); );
final Application firstApplication = data.applications.stream().filter(app -> app.getName().equals("first application")).findFirst().orElse(null); final Application firstApplication = data.applications.stream().filter(appFirst -> appFirst.getName().equals("first application")).findFirst().orElse(null);
assert firstApplication != null; assert firstApplication != null;
assertThat(firstApplication.getPages().stream().filter(ApplicationPage::isDefault).count()).isEqualTo(1); assertThat(firstApplication.getPages().stream().filter(ApplicationPage::isDefault).count()).isEqualTo(1);
final NewPage newPage = mongoTemplate.findOne(Query.query(Criteria.where("applicationId").is(firstApplication.getId()).and("unpublishedPage.name").is("A New Page")), NewPage.class); final NewPage newPage1 = mongoTemplate.findOne(Query.query(Criteria.where("applicationId").is(firstApplication.getId()).and("unpublishedPage.name").is("A New Page")), NewPage.class);
assert newPage != null; assert newPage1 != null;
log.debug("new page is : {}", newPage.toString()); final String actionId = newPage1.getUnpublishedPage().getLayouts().get(0).getLayoutOnLoadActions().get(0).iterator().next().getId();
final String actionId = newPage.getUnpublishedPage().getLayouts().get(0).getLayoutOnLoadActions().get(0).iterator().next().getId(); final NewAction newPageAction1 = mongoTemplate.findOne(Query.query(Criteria.where("id").is(actionId)), NewAction.class);
final NewAction newPageAction = mongoTemplate.findOne(Query.query(Criteria.where("id").is(actionId)), NewAction.class); assert newPageAction1 != null;
assert newPageAction != null; assertThat(newPageAction1.getOrganizationId()).isEqualTo(data.organization.getId());
assertThat(newPageAction.getOrganizationId()).isEqualTo(data.organization.getId());
assertThat(data.datasources).hasSize(2); assertThat(data.datasources).hasSize(2);
assertThat(map(data.datasources, Datasource::getName)).containsExactlyInAnyOrder( assertThat(map(data.datasources, Datasource::getName)).containsExactlyInAnyOrder(
@ -753,16 +764,18 @@ public class ExamplesOrganizationClonerTests {
"datasource 2" "datasource 2"
); );
assertThat(data.actions).hasSize(5); assertThat(data.actions).hasSize(4);
assertThat(getUnpublishedActionName(data.actions)).containsExactlyInAnyOrder( assertThat(getUnpublishedActionName(data.actions)).containsExactlyInAnyOrder(
"newPageAction", "newPageAction",
"action1", "action1",
"action2",
"action3", "action3",
"action4" "run"
); );
assertThat(data.actionCollections).hasSize(1);
assertThat(data.actionCollections.get(0).getActionIds()).hasSize(1);
}) })
.verifyComplete(); .verifyComplete();
} }
@Test @Test
@ -1014,4 +1027,13 @@ public class ExamplesOrganizationClonerTests {
.flatMap(page -> newActionService.getUnpublishedActions(new LinkedMultiValueMap<>( .flatMap(page -> newActionService.getUnpublishedActions(new LinkedMultiValueMap<>(
Map.of(FieldName.PAGE_ID, Collections.singletonList(page.getId()))))); Map.of(FieldName.PAGE_ID, Collections.singletonList(page.getId())))));
} }
private Flux<ActionCollectionDTO> getActionCollectionsInOrganization(Organization organization) {
return applicationService
.findByOrganizationId(organization.getId(), READ_APPLICATIONS)
// fetch the unpublished pages
.flatMap(application -> newPageService.findByApplicationId(application.getId(), READ_PAGES, false))
.flatMap(page -> actionCollectionService.getActionCollectionsByViewMode(new LinkedMultiValueMap<>(
Map.of(FieldName.PAGE_ID, Collections.singletonList(page.getId()))), false));
}
} }