Merge branch 'release'
This commit is contained in:
commit
ecf07e054e
17
.github/workflows/github-release.yml
vendored
17
.github/workflows/github-release.yml
vendored
|
|
@ -121,6 +121,21 @@ jobs:
|
|||
|
||||
steps:
|
||||
# Creating the release on Github
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
|
||||
|
||||
# If the tag has the string "beta", then mark the Github release as a pre-release
|
||||
- name: Get the version
|
||||
id: get_release
|
||||
run: |
|
||||
STATUS=false
|
||||
if [[ ! ${{steps.get_version.outputs.tag}} == *"beta"* ]]; then
|
||||
STATUS=true
|
||||
fi
|
||||
|
||||
echo ::set-output name=status::${STATUS}
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
|
|
@ -130,5 +145,5 @@ jobs:
|
|||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
prerelease: ${{steps.get_release.outputs.status}}
|
||||
|
||||
|
|
@ -24,6 +24,7 @@ public class FieldName {
|
|||
public static String PROVIDER_ID = "providerId";
|
||||
public static String CATEGORY = "category";
|
||||
public static String PAGE = "page";
|
||||
public static String PAGES = "pages";
|
||||
public static String SIZE = "size";
|
||||
public static String ROLE = "role";
|
||||
public static String DEFAULT_WIDGET_NAME = "MainContainer";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.appsmith.server.domains;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
|
@ -9,9 +10,11 @@ import lombok.ToString;
|
|||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ApplicationPage {
|
||||
|
||||
String id;
|
||||
|
||||
Boolean isDefault;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package com.appsmith.server.repositories;
|
|||
|
||||
import com.appsmith.server.acl.AclPermission;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.Page;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
|
@ -16,4 +18,6 @@ public interface CustomApplicationRepository extends AppsmithRepository<Applicat
|
|||
Flux<Application> findByOrganizationId(String orgId, AclPermission permission);
|
||||
|
||||
Flux<Application> findByMultipleOrganizationIds(Set<String> orgIds, AclPermission permission);
|
||||
|
||||
Mono<UpdateResult> addPageToApplication(Application application, Page page, boolean isDefault);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,20 @@ package com.appsmith.server.repositories;
|
|||
|
||||
import com.appsmith.server.acl.AclPermission;
|
||||
import com.appsmith.server.acl.PolicyGenerator;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.ApplicationPage;
|
||||
import com.appsmith.server.domains.Page;
|
||||
import com.appsmith.server.domains.QApplication;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
|
@ -64,4 +70,14 @@ public class CustomApplicationRepositoryImpl extends BaseAppsmithRepositoryImpl<
|
|||
return queryAll(List.of(orgIdsCriteria), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UpdateResult> addPageToApplication(Application application, Page page, boolean isDefault) {
|
||||
final ApplicationPage applicationPage = new ApplicationPage(page.getId(), isDefault);
|
||||
return mongoOperations.updateFirst(
|
||||
Query.query(getIdCriteria(application.getId())),
|
||||
new Update().addToSet(FieldName.PAGES, applicationPage),
|
||||
Application.class
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@ package com.appsmith.server.services;
|
|||
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.Page;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface ApplicationPageService {
|
||||
Mono<Page> createPage(Page page);
|
||||
|
||||
Mono<Application> addPageToApplication(Mono<Application> applicationMono, Page page, Boolean isDefault);
|
||||
Mono<UpdateResult> addPageToApplication(Application application, Page page, Boolean isDefault);
|
||||
|
||||
Mono<Page> getPage(String pageId, Boolean viewMode);
|
||||
|
||||
|
|
@ -19,5 +20,7 @@ public interface ApplicationPageService {
|
|||
|
||||
Mono<Application> makePageDefault(String applicationId, String pageId);
|
||||
|
||||
Mono<Application> cloneApplication(Application application);
|
||||
|
||||
Mono<Application> deleteApplication(String id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,15 @@ import com.appsmith.server.domains.Page;
|
|||
import com.appsmith.server.domains.User;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import com.appsmith.server.repositories.ApplicationRepository;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -40,18 +44,22 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
|
|||
private final AnalyticsService analyticsService;
|
||||
private final PolicyGenerator policyGenerator;
|
||||
|
||||
private final ApplicationRepository applicationRepository;
|
||||
|
||||
public ApplicationPageServiceImpl(ApplicationService applicationService,
|
||||
PageService pageService,
|
||||
SessionUserService sessionUserService,
|
||||
OrganizationService organizationService,
|
||||
AnalyticsService analyticsService,
|
||||
PolicyGenerator policyGenerator) {
|
||||
PolicyGenerator policyGenerator,
|
||||
ApplicationRepository applicationRepository) {
|
||||
this.applicationService = applicationService;
|
||||
this.pageService = pageService;
|
||||
this.sessionUserService = sessionUserService;
|
||||
this.organizationService = organizationService;
|
||||
this.analyticsService = analyticsService;
|
||||
this.policyGenerator = policyGenerator;
|
||||
this.applicationRepository = applicationRepository;
|
||||
}
|
||||
|
||||
public Mono<Page> createPage(Page page) {
|
||||
|
|
@ -87,34 +95,31 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
|
|||
return pageMono
|
||||
.flatMap(pageService::createDefault)
|
||||
//After the page has been saved, update the application (save the page id inside the application)
|
||||
.flatMap(savedPage ->
|
||||
addPageToApplication(applicationMono, savedPage, false)
|
||||
.thenReturn(savedPage));
|
||||
.zipWith(applicationMono)
|
||||
.flatMap(tuple -> {
|
||||
final Page savedPage = tuple.getT1();
|
||||
final Application application = tuple.getT2();
|
||||
return addPageToApplication(application, savedPage, false)
|
||||
.thenReturn(savedPage);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called during page create in Page Service. It adds the newly created
|
||||
* page to its ApplicationPages list.
|
||||
* This function is called during page create in Page Service. It adds the given page to its ApplicationPages list.
|
||||
* Note: It is assumed here that `application` is already checked for the MANAGE_APPLICATIONS policy.
|
||||
*
|
||||
* @param applicationMono
|
||||
* @param page
|
||||
* @return Updated application
|
||||
* @param application Application to which the page will be added. Should have an `id` already.
|
||||
* @param page Page to be added to the application. Should have an `id` already.
|
||||
* @return UpdateResult object with details on how many documents have been updated, which should be 0 or 1.
|
||||
*/
|
||||
public Mono<Application> addPageToApplication(Mono<Application> applicationMono, Page page, Boolean isDefault) {
|
||||
return applicationMono
|
||||
.map(application -> {
|
||||
List<ApplicationPage> applicationPages = application.getPages();
|
||||
if (applicationPages == null) {
|
||||
applicationPages = new ArrayList<>();
|
||||
@Override
|
||||
public Mono<UpdateResult> addPageToApplication(Application application, Page page, Boolean isDefault) {
|
||||
return applicationRepository.addPageToApplication(application, page, isDefault)
|
||||
.doOnSuccess(result -> {
|
||||
if (result.getModifiedCount() != 1) {
|
||||
log.error("Add page to application didn't update anything, probably because application wasn't found.");
|
||||
}
|
||||
ApplicationPage applicationPage = new ApplicationPage();
|
||||
applicationPage.setId(page.getId());
|
||||
applicationPage.setIsDefault(isDefault);
|
||||
applicationPages.add(applicationPage);
|
||||
application.setPages(applicationPages);
|
||||
return application;
|
||||
})
|
||||
.flatMap(applicationService::save);
|
||||
});
|
||||
}
|
||||
|
||||
public Mono<Page> getPage(String pageId, Boolean viewMode) {
|
||||
|
|
@ -246,10 +251,53 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
|
|||
|
||||
return pageService
|
||||
.createDefault(page)
|
||||
.flatMap(savedPage -> addPageToApplication(Mono.just(savedApplication), savedPage, true));
|
||||
.flatMap(savedPage -> addPageToApplication(savedApplication, savedPage, true))
|
||||
.then(applicationService.findById(savedApplication.getId(), READ_APPLICATIONS));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Application> cloneApplication(Application application) {
|
||||
if (!StringUtils.hasText(application.getName())) {
|
||||
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.NAME));
|
||||
}
|
||||
|
||||
String orgId = application.getOrganizationId();
|
||||
if (!StringUtils.hasText(orgId)) {
|
||||
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ORGANIZATION_ID));
|
||||
}
|
||||
|
||||
// Clean the object so that it will be saved as a new application for the currently signed in user.
|
||||
application.setId(null);
|
||||
application.setPolicies(new HashSet<>());
|
||||
application.setPages(new ArrayList<>());
|
||||
|
||||
Mono<User> userMono = sessionUserService.getCurrentUser().cache();
|
||||
Mono<Application> applicationWithPoliciesMono = userMono
|
||||
.flatMap(user -> {
|
||||
Mono<Organization> orgMono = organizationService.findById(orgId, ORGANIZATION_MANAGE_APPLICATIONS)
|
||||
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.ORGANIZATION, orgId)));
|
||||
|
||||
return orgMono.map(org -> {
|
||||
application.setOrganizationId(org.getId());
|
||||
// At the organization level, filter out all the application specific policies and apply them
|
||||
// to the new application that we are creating.
|
||||
Set<Policy> policySet = org.getPolicies().stream()
|
||||
.filter(policy ->
|
||||
policy.getPermission().equals(ORGANIZATION_MANAGE_APPLICATIONS.getValue()) ||
|
||||
policy.getPermission().equals(ORGANIZATION_READ_APPLICATIONS.getValue())
|
||||
).collect(Collectors.toSet());
|
||||
|
||||
Set<Policy> documentPolicies = policyGenerator.getAllChildPolicies(policySet, Organization.class, Application.class);
|
||||
application.setPolicies(documentPolicies);
|
||||
return application;
|
||||
});
|
||||
});
|
||||
|
||||
return applicationWithPoliciesMono
|
||||
.flatMap(applicationService::createDefault);
|
||||
}
|
||||
|
||||
private void generateAndSetPagePolicies(Application application, User user, Page page) {
|
||||
Set<Policy> policySet = application.getPolicies().stream()
|
||||
.filter(policy -> policy.getPermission().equals(MANAGE_APPLICATIONS.getValue())
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package com.appsmith.server.solutions;
|
|||
import com.appsmith.external.models.BaseDomain;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.domains.Action;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.Datasource;
|
||||
import com.appsmith.server.domains.Organization;
|
||||
import com.appsmith.server.domains.Page;
|
||||
import com.appsmith.server.domains.User;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
|
|
@ -94,7 +96,8 @@ public class ExamplesOrganizationCloner {
|
|||
* @param user The user who will own the new cloned organization.
|
||||
* @return Publishes the newly created organization.
|
||||
*/
|
||||
private Mono<Organization> cloneOrganizationForUser(String templateOrganizationId, User user) {
|
||||
public Mono<Organization> cloneOrganizationForUser(String templateOrganizationId, User user) {
|
||||
log.info("Cloning organization id {}", templateOrganizationId);
|
||||
return organizationRepository
|
||||
.findById(templateOrganizationId)
|
||||
.doOnSuccess(organization -> {
|
||||
|
|
@ -144,46 +147,70 @@ public class ExamplesOrganizationCloner {
|
|||
.findByOrganizationIdAndIsPublicTrue(fromOrganizationId)
|
||||
.flatMap(application -> {
|
||||
final String templateApplicationId = application.getId();
|
||||
makePristine(application);
|
||||
application.setOrganizationId(toOrganizationId);
|
||||
if (!CollectionUtils.isEmpty(application.getPages())) {
|
||||
application.getPages().clear();
|
||||
}
|
||||
return Flux.combineLatest(
|
||||
pageRepository.findByApplicationId(templateApplicationId),
|
||||
applicationPageService.createApplication(application).cache(),
|
||||
(page, savedApplication) -> {
|
||||
log.info("Cloned application {} into new application {}", templateApplicationId, savedApplication.getId());
|
||||
page.setApplicationId(savedApplication.getId());
|
||||
return page;
|
||||
}
|
||||
);
|
||||
return doCloneApplication(application, templateApplicationId);
|
||||
})
|
||||
.flatMap(page -> {
|
||||
final String templatePageId = page.getId();
|
||||
makePristine(page);
|
||||
return Flux.combineLatest(
|
||||
actionRepository.findByPageId(templatePageId),
|
||||
applicationPageService.createPage(page).cache(),
|
||||
(action, savedPage) -> {
|
||||
action.setPageId(savedPage.getId());
|
||||
return action;
|
||||
}
|
||||
);
|
||||
return applicationPageService
|
||||
.createPage(page)
|
||||
.flatMap(page1 -> {
|
||||
log.info("Cloned into new page {}", page1);
|
||||
return applicationRepository.findById(page.getApplicationId())
|
||||
.map(application -> {
|
||||
log.info("Application after page got cloned: {}", application);
|
||||
return page1;
|
||||
});
|
||||
})
|
||||
.flatMapMany(
|
||||
savedPage -> actionRepository
|
||||
.findByPageId(templatePageId)
|
||||
.map(action -> {
|
||||
log.info("Preparing action for cloning {} {}.", action.getName(), action.getId());
|
||||
action.setPageId(savedPage.getId());
|
||||
return action;
|
||||
})
|
||||
);
|
||||
})
|
||||
.zipWith(cloneDatasourcesMono)
|
||||
.flatMap(tuple -> {
|
||||
final Action action = tuple.getT1();
|
||||
final Map<String, Datasource> newDatasourcesByTemplateId = tuple.getT2();
|
||||
.flatMap(action -> {
|
||||
log.info("Creating clone of action {}", action.getId());
|
||||
makePristine(action);
|
||||
action.setOrganizationId(toOrganizationId);
|
||||
action.setCollectionId(null);
|
||||
action.setDatasource(newDatasourcesByTemplateId.get(action.getDatasource().getId()));
|
||||
return actionService.create(action);
|
||||
Mono<Action> actionMono = Mono.just(action);
|
||||
final Datasource datasourceInsideAction = action.getDatasource();
|
||||
if (datasourceInsideAction != null) {
|
||||
if (datasourceInsideAction.getId() != null) {
|
||||
actionMono = cloneDatasourcesMono
|
||||
.map(newDatasourcesByTemplateId -> {
|
||||
action.setDatasource(newDatasourcesByTemplateId.get(datasourceInsideAction.getId()));
|
||||
return action;
|
||||
});
|
||||
} else {
|
||||
datasourceInsideAction.setOrganizationId(toOrganizationId);
|
||||
}
|
||||
}
|
||||
return actionMono.flatMap(actionService::create);
|
||||
})
|
||||
.then(cloneDatasourcesMono) // Run the datasource cloning mono if it isn't already done.
|
||||
.then();
|
||||
}
|
||||
|
||||
private Flux<Page> doCloneApplication(Application application, String templateApplicationId) {
|
||||
return applicationPageService
|
||||
.cloneApplication(application)
|
||||
.flatMapMany(
|
||||
savedApplication -> pageRepository
|
||||
.findByApplicationId(templateApplicationId)
|
||||
.map(page -> {
|
||||
log.info("Preparing page for cloning {} {}.", page.getName(), page.getId());
|
||||
page.setApplicationId(savedApplication.getId());
|
||||
return page;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone all the datasources (except deleted ones) from one organization to another. Publishes a map where the keys
|
||||
* are IDs of datasources that were copied (source IDs), and the values are the cloned datasource objects which
|
||||
|
|
@ -202,7 +229,7 @@ public class ExamplesOrganizationCloner {
|
|||
}
|
||||
makePristine(datasource);
|
||||
datasource.setOrganizationId(toOrganizationId);
|
||||
datasource.setName(datasource.getName() + " cloned " + Math.random());
|
||||
datasource.setName(datasource.getName());
|
||||
return Mono.zip(
|
||||
Mono.just(templateDatasourceId),
|
||||
datasourceService.create(datasource)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,556 @@
|
|||
package com.appsmith.server.solutions;
|
||||
|
||||
import com.appsmith.external.models.DatasourceConfiguration;
|
||||
import com.appsmith.external.models.Property;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.domains.Action;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.Datasource;
|
||||
import com.appsmith.server.domains.Organization;
|
||||
import com.appsmith.server.domains.Page;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.helpers.MockPluginExecutor;
|
||||
import com.appsmith.server.helpers.PluginExecutorHelper;
|
||||
import com.appsmith.server.repositories.PluginRepository;
|
||||
import com.appsmith.server.services.ActionCollectionService;
|
||||
import com.appsmith.server.services.ActionService;
|
||||
import com.appsmith.server.services.ApplicationPageService;
|
||||
import com.appsmith.server.services.ApplicationService;
|
||||
import com.appsmith.server.services.DatasourceService;
|
||||
import com.appsmith.server.services.OrganizationService;
|
||||
import com.appsmith.server.services.PageService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
import com.appsmith.server.services.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
|
||||
import static com.appsmith.server.acl.AclPermission.READ_DATASOURCES;
|
||||
import static com.appsmith.server.acl.AclPermission.READ_PAGES;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@Slf4j
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@DirtiesContext
|
||||
public class ExamplesOrganizationClonerTests {
|
||||
|
||||
@Autowired
|
||||
UserService userService;
|
||||
|
||||
@Autowired
|
||||
private ExamplesOrganizationCloner examplesOrganizationCloner;
|
||||
|
||||
@Autowired
|
||||
private ApplicationService applicationService;
|
||||
|
||||
@Autowired
|
||||
private DatasourceService datasourceService;
|
||||
|
||||
@Autowired
|
||||
private OrganizationService organizationService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationPageService applicationPageService;
|
||||
|
||||
@Autowired
|
||||
private SessionUserService sessionUserService;
|
||||
|
||||
@Autowired
|
||||
private ActionService actionService;
|
||||
|
||||
@Autowired
|
||||
private PageService pageService;
|
||||
|
||||
@Autowired
|
||||
private ActionCollectionService actionCollectionService;
|
||||
|
||||
@Autowired
|
||||
private PluginRepository pluginRepository;
|
||||
|
||||
@MockBean
|
||||
private PluginExecutorHelper pluginExecutorHelper;
|
||||
|
||||
private Plugin installedPlugin;
|
||||
|
||||
private static class OrganizationData {
|
||||
Organization organization;
|
||||
List<Application> applications = new ArrayList<>();
|
||||
List<Datasource> datasources = new ArrayList<>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Mono<OrganizationData> loadOrganizationData(Organization organization) {
|
||||
final OrganizationData data = new OrganizationData();
|
||||
data.organization = organization;
|
||||
|
||||
return Mono
|
||||
.when(
|
||||
applicationService
|
||||
.findByOrganizationId(organization.getId(), READ_APPLICATIONS)
|
||||
.map(data.applications::add),
|
||||
datasourceService
|
||||
.findAllByOrganizationId(organization.getId(), READ_DATASOURCES)
|
||||
.map(data.datasources::add),
|
||||
getActionsInOrganization(organization)
|
||||
.map(data.actions::add)
|
||||
)
|
||||
.thenReturn(data);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any())).thenReturn(Mono.just(new MockPluginExecutor()));
|
||||
installedPlugin = pluginRepository.findByPackageName("installed-plugin").block();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void cloneEmptyOrganization() {
|
||||
Organization newOrganization = new Organization();
|
||||
newOrganization.setName("Template Organization");
|
||||
final Mono<OrganizationData> resultMono = organizationService.create(newOrganization)
|
||||
.zipWith(sessionUserService.getCurrentUser())
|
||||
.flatMap(tuple ->
|
||||
examplesOrganizationCloner.cloneOrganizationForUser(tuple.getT1().getId(), tuple.getT2()))
|
||||
.flatMap(this::loadOrganizationData);
|
||||
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(data -> {
|
||||
assertThat(data.organization).isNotNull();
|
||||
assertThat(data.organization.getId()).isNotNull();
|
||||
assertThat(data.organization.getName()).isEqualTo("api_user's Examples");
|
||||
assertThat(data.organization.getPolicies()).isNotEmpty();
|
||||
|
||||
assertThat(data.applications).isEmpty();
|
||||
assertThat(data.datasources).isEmpty();
|
||||
assertThat(data.actions).isEmpty();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void cloneOrganizationWithItsContents() {
|
||||
Organization newOrganization = new Organization();
|
||||
newOrganization.setName("Template Organization");
|
||||
final Mono<OrganizationData> resultMono = Mono
|
||||
.zip(
|
||||
organizationService.create(newOrganization),
|
||||
sessionUserService.getCurrentUser()
|
||||
)
|
||||
.flatMap(tuple -> {
|
||||
final Organization organization = tuple.getT1();
|
||||
Application app1 = new Application();
|
||||
app1.setName("1 - public app");
|
||||
app1.setOrganizationId(organization.getId());
|
||||
app1.setIsPublic(true);
|
||||
|
||||
Application app2 = new Application();
|
||||
app2.setOrganizationId(organization.getId());
|
||||
app2.setName("2 - private app");
|
||||
|
||||
return Mono.when(
|
||||
applicationPageService.createApplication(app1),
|
||||
applicationPageService.createApplication(app2)
|
||||
).then(examplesOrganizationCloner.cloneOrganizationForUser(organization.getId(), tuple.getT2()));
|
||||
})
|
||||
.flatMap(this::loadOrganizationData);
|
||||
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(data -> {
|
||||
assertThat(data.organization).isNotNull();
|
||||
assertThat(data.organization.getId()).isNotNull();
|
||||
assertThat(data.organization.getName()).isEqualTo("api_user's Examples");
|
||||
assertThat(data.organization.getPolicies()).isNotEmpty();
|
||||
|
||||
assertThat(data.applications).hasSize(1);
|
||||
assertThat(map(data.applications, Application::getName)).containsExactly("1 - public app");
|
||||
assertThat(data.applications.get(0).getPages()).hasSize(1);
|
||||
|
||||
assertThat(data.datasources).isEmpty();
|
||||
assertThat(data.actions).isEmpty();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void cloneOrganizationWithOnlyPublicApplications() {
|
||||
Organization newOrganization = new Organization();
|
||||
newOrganization.setName("Template Organization 2");
|
||||
final Mono<OrganizationData> resultMono = Mono
|
||||
.zip(
|
||||
organizationService.create(newOrganization),
|
||||
sessionUserService.getCurrentUser()
|
||||
)
|
||||
.flatMap(tuple -> {
|
||||
final Organization organization = tuple.getT1();
|
||||
|
||||
Application app1 = new Application();
|
||||
app1.setName("1 - public app more");
|
||||
app1.setOrganizationId(organization.getId());
|
||||
app1.setIsPublic(true);
|
||||
|
||||
Application app2 = new Application();
|
||||
app2.setOrganizationId(organization.getId());
|
||||
app2.setName("2 - another public app more");
|
||||
app2.setIsPublic(true);
|
||||
|
||||
return Mono.zip(
|
||||
applicationPageService.createApplication(app1),
|
||||
applicationPageService.createApplication(app2).flatMap(application -> {
|
||||
final Page newPage = new Page();
|
||||
newPage.setName("The New Page");
|
||||
newPage.setApplicationId(application.getId());
|
||||
return applicationPageService.createPage(newPage);
|
||||
})
|
||||
).then(examplesOrganizationCloner.cloneOrganizationForUser(organization.getId(), tuple.getT2()));
|
||||
})
|
||||
.flatMap(this::loadOrganizationData);
|
||||
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(data -> {
|
||||
assertThat(data.organization).isNotNull();
|
||||
assertThat(data.organization.getId()).isNotNull();
|
||||
assertThat(data.organization.getName()).isEqualTo("api_user's Examples");
|
||||
assertThat(data.organization.getPolicies()).isNotEmpty();
|
||||
|
||||
assertThat(data.applications).hasSize(2);
|
||||
assertThat(map(data.applications, Application::getName)).containsExactlyInAnyOrder(
|
||||
"1 - public app more",
|
||||
"2 - another public app more"
|
||||
);
|
||||
|
||||
for (final Application app : data.applications) {
|
||||
if ("2 - another public app more".equals(app.getName())) {
|
||||
assertThat(app.getPages()).hasSize(2);
|
||||
} else {
|
||||
assertThat(app.getPages()).hasSize(1);
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(data.datasources).isEmpty();
|
||||
assertThat(data.actions).isEmpty();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void cloneOrganizationWithOnlyPrivateApplications() {
|
||||
Organization newOrganization = new Organization();
|
||||
newOrganization.setName("Template Organization 2");
|
||||
final Mono<OrganizationData> resultMono = Mono
|
||||
.zip(
|
||||
organizationService.create(newOrganization),
|
||||
sessionUserService.getCurrentUser()
|
||||
)
|
||||
.flatMap(tuple -> {
|
||||
final Organization organization = tuple.getT1();
|
||||
|
||||
Application app1 = new Application();
|
||||
app1.setName("1 - private app more");
|
||||
app1.setOrganizationId(organization.getId());
|
||||
|
||||
Application app2 = new Application();
|
||||
app2.setOrganizationId(organization.getId());
|
||||
app2.setName("2 - another private app more");
|
||||
|
||||
return Mono.when(
|
||||
applicationPageService.createApplication(app1),
|
||||
applicationPageService.createApplication(app2)
|
||||
).then(examplesOrganizationCloner.cloneOrganizationForUser(organization.getId(), tuple.getT2()));
|
||||
})
|
||||
.flatMap(this::loadOrganizationData);
|
||||
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(data -> {
|
||||
assertThat(data.organization).isNotNull();
|
||||
assertThat(data.organization.getId()).isNotNull();
|
||||
assertThat(data.organization.getName()).isEqualTo("api_user's Examples");
|
||||
assertThat(data.organization.getPolicies()).isNotEmpty();
|
||||
|
||||
assertThat(data.applications).isEmpty();
|
||||
assertThat(data.datasources).isEmpty();
|
||||
assertThat(data.actions).isEmpty();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void cloneOrganizationWithOnlyDatasources() {
|
||||
Organization newOrganization = new Organization();
|
||||
newOrganization.setName("Template Organization 2");
|
||||
final Mono<OrganizationData> resultMono = Mono
|
||||
.zip(
|
||||
organizationService.create(newOrganization),
|
||||
sessionUserService.getCurrentUser()
|
||||
)
|
||||
.flatMap(tuple -> {
|
||||
final Organization organization = tuple.getT1();
|
||||
|
||||
final Datasource ds1 = new Datasource();
|
||||
ds1.setName("datasource 1");
|
||||
ds1.setOrganizationId(organization.getId());
|
||||
final DatasourceConfiguration datasourceConfiguration = new DatasourceConfiguration();
|
||||
ds1.setDatasourceConfiguration(datasourceConfiguration);
|
||||
datasourceConfiguration.setUrl("http://httpbin.org/get");
|
||||
datasourceConfiguration.setHeaders(List.of(
|
||||
new Property("X-Answer", "42")
|
||||
));
|
||||
|
||||
final Datasource ds2 = new Datasource();
|
||||
ds2.setName("datasource 2");
|
||||
ds2.setOrganizationId(organization.getId());
|
||||
|
||||
return Mono.when(
|
||||
datasourceService.create(ds1),
|
||||
datasourceService.create(ds2)
|
||||
).then(examplesOrganizationCloner.cloneOrganizationForUser(organization.getId(), tuple.getT2()));
|
||||
})
|
||||
.flatMap(this::loadOrganizationData);
|
||||
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(data -> {
|
||||
assertThat(data.organization).isNotNull();
|
||||
assertThat(data.organization.getId()).isNotNull();
|
||||
assertThat(data.organization.getName()).isEqualTo("api_user's Examples");
|
||||
assertThat(data.organization.getPolicies()).isNotEmpty();
|
||||
|
||||
assertThat(data.datasources).hasSize(2);
|
||||
assertThat(map(data.datasources, Datasource::getName)).containsExactlyInAnyOrder(
|
||||
"datasource 1",
|
||||
"datasource 2"
|
||||
);
|
||||
|
||||
final Datasource ds1 = data.datasources.stream()
|
||||
.filter(datasource -> "datasource 1".equals(datasource.getName()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
assertThat(ds1.getDatasourceConfiguration().getUrl()).isEqualTo("http://httpbin.org/get");
|
||||
assertThat(ds1.getDatasourceConfiguration().getHeaders()).containsOnly(
|
||||
new Property("X-Answer", "42")
|
||||
);
|
||||
|
||||
assertThat(data.applications).isEmpty();
|
||||
assertThat(data.actions).isEmpty();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void cloneOrganizationWithDatasourcesAndApplications() {
|
||||
Organization newOrganization = new Organization();
|
||||
newOrganization.setName("Template Organization 2");
|
||||
final Mono<OrganizationData> resultMono = Mono
|
||||
.zip(
|
||||
organizationService.create(newOrganization),
|
||||
sessionUserService.getCurrentUser()
|
||||
)
|
||||
.flatMap(tuple -> {
|
||||
final Organization organization = tuple.getT1();
|
||||
|
||||
final Application app1 = new Application();
|
||||
app1.setName("first application");
|
||||
app1.setOrganizationId(organization.getId());
|
||||
app1.setIsPublic(true);
|
||||
|
||||
final Application app2 = new Application();
|
||||
app2.setName("second application");
|
||||
app2.setOrganizationId(organization.getId());
|
||||
app2.setIsPublic(true);
|
||||
|
||||
final Datasource ds1 = new Datasource();
|
||||
ds1.setName("datasource 1");
|
||||
ds1.setOrganizationId(organization.getId());
|
||||
|
||||
final Datasource ds2 = new Datasource();
|
||||
ds2.setName("datasource 2");
|
||||
ds2.setOrganizationId(organization.getId());
|
||||
|
||||
return Mono.when(
|
||||
applicationPageService.createApplication(app1),
|
||||
applicationPageService.createApplication(app2),
|
||||
datasourceService.create(ds1),
|
||||
datasourceService.create(ds2)
|
||||
).then(examplesOrganizationCloner.cloneOrganizationForUser(organization.getId(), tuple.getT2()));
|
||||
})
|
||||
.flatMap(this::loadOrganizationData);
|
||||
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(data -> {
|
||||
assertThat(data.organization).isNotNull();
|
||||
assertThat(data.organization.getId()).isNotNull();
|
||||
assertThat(data.organization.getName()).isEqualTo("api_user's Examples");
|
||||
assertThat(data.organization.getPolicies()).isNotEmpty();
|
||||
|
||||
assertThat(data.applications).hasSize(2);
|
||||
assertThat(map(data.applications, Application::getName)).containsExactlyInAnyOrder(
|
||||
"first application",
|
||||
"second application"
|
||||
);
|
||||
|
||||
assertThat(data.datasources).hasSize(2);
|
||||
assertThat(map(data.datasources, Datasource::getName)).containsExactlyInAnyOrder(
|
||||
"datasource 1",
|
||||
"datasource 2"
|
||||
);
|
||||
|
||||
assertThat(data.actions).isEmpty();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void cloneOrganizationWithDatasourcesAndApplicationsAndActions() {
|
||||
Organization newOrganization = new Organization();
|
||||
newOrganization.setName("Template Organization 2");
|
||||
final Mono<OrganizationData> resultMono = Mono
|
||||
.zip(
|
||||
organizationService.create(newOrganization),
|
||||
sessionUserService.getCurrentUser()
|
||||
)
|
||||
.flatMap(tuple -> {
|
||||
final Organization organization = tuple.getT1();
|
||||
|
||||
final Application app1 = new Application();
|
||||
app1.setName("first application");
|
||||
app1.setOrganizationId(organization.getId());
|
||||
app1.setIsPublic(true);
|
||||
|
||||
final Application app2 = new Application();
|
||||
app2.setName("second application");
|
||||
app2.setOrganizationId(organization.getId());
|
||||
app2.setIsPublic(true);
|
||||
|
||||
final Datasource ds1 = new Datasource();
|
||||
ds1.setName("datasource 1");
|
||||
ds1.setOrganizationId(organization.getId());
|
||||
ds1.setPluginId(installedPlugin.getId());
|
||||
|
||||
final Datasource ds2 = new Datasource();
|
||||
ds2.setName("datasource 2");
|
||||
ds2.setOrganizationId(organization.getId());
|
||||
ds2.setPluginId(installedPlugin.getId());
|
||||
|
||||
return Mono
|
||||
.zip(
|
||||
applicationPageService.createApplication(app1),
|
||||
applicationPageService.createApplication(app2),
|
||||
datasourceService.create(ds1),
|
||||
datasourceService.create(ds2)
|
||||
)
|
||||
.flatMap(tuple1 -> {
|
||||
final Application app = tuple1.getT1();
|
||||
final String pageId1 = app.getPages().get(0).getId();
|
||||
final Datasource ds1Again = tuple1.getT3();
|
||||
|
||||
final Action action1 = new Action();
|
||||
action1.setName("action1");
|
||||
action1.setPageId(pageId1);
|
||||
action1.setOrganizationId(organization.getId());
|
||||
action1.setDatasource(ds1Again);
|
||||
action1.setPluginId(installedPlugin.getId());
|
||||
|
||||
final Action action2 = new Action();
|
||||
action2.setPageId(pageId1);
|
||||
action2.setName("action2");
|
||||
action2.setOrganizationId(organization.getId());
|
||||
action2.setDatasource(ds1Again);
|
||||
action2.setPluginId(installedPlugin.getId());
|
||||
|
||||
final Application app2Again = tuple1.getT2();
|
||||
final String pageId2 = app2Again.getPages().get(0).getId();
|
||||
final Datasource ds2Again = tuple1.getT4();
|
||||
|
||||
final Action action3 = new Action();
|
||||
action3.setName("action3");
|
||||
action3.setPageId(pageId2);
|
||||
action3.setOrganizationId(organization.getId());
|
||||
action3.setDatasource(ds2Again);
|
||||
action3.setPluginId(installedPlugin.getId());
|
||||
|
||||
final Action action4 = new Action();
|
||||
action4.setPageId(pageId2);
|
||||
action4.setName("action4");
|
||||
action4.setOrganizationId(organization.getId());
|
||||
action4.setDatasource(ds2Again);
|
||||
action4.setPluginId(installedPlugin.getId());
|
||||
|
||||
return Mono.when(
|
||||
actionCollectionService.createAction(action1),
|
||||
actionCollectionService.createAction(action2),
|
||||
actionCollectionService.createAction(action3),
|
||||
actionCollectionService.createAction(action4)
|
||||
);
|
||||
})
|
||||
.then(examplesOrganizationCloner.cloneOrganizationForUser(organization.getId(), tuple.getT2()));
|
||||
})
|
||||
.flatMap(this::loadOrganizationData);
|
||||
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(data -> {
|
||||
assertThat(data.organization).isNotNull();
|
||||
assertThat(data.organization.getId()).isNotNull();
|
||||
assertThat(data.organization.getName()).isEqualTo("api_user's Examples");
|
||||
assertThat(data.organization.getPolicies()).isNotEmpty();
|
||||
|
||||
assertThat(data.applications).hasSize(2);
|
||||
assertThat(map(data.applications, Application::getName)).containsExactlyInAnyOrder(
|
||||
"first application",
|
||||
"second application"
|
||||
);
|
||||
|
||||
assertThat(data.datasources).hasSize(2);
|
||||
assertThat(map(data.datasources, Datasource::getName)).containsExactlyInAnyOrder(
|
||||
"datasource 1",
|
||||
"datasource 2"
|
||||
);
|
||||
|
||||
assertThat(data.actions).hasSize(4);
|
||||
assertThat(map(data.actions, Action::getName)).containsExactlyInAnyOrder(
|
||||
"action1",
|
||||
"action2",
|
||||
"action3",
|
||||
"action4"
|
||||
);
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
private <InType, OutType> List<OutType> map(List<InType> list, Function<InType, OutType> fn) {
|
||||
return list.stream().map(fn).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Flux<Action> getActionsInOrganization(Organization organization) {
|
||||
return applicationService
|
||||
.findByOrganizationId(organization.getId(), READ_APPLICATIONS)
|
||||
.flatMap(application -> pageService.findByApplicationId(application.getId(), READ_PAGES))
|
||||
.flatMap(page -> actionService.get(new LinkedMultiValueMap<String, String>(
|
||||
Map.of(FieldName.PAGE_ID, Collections.singletonList(page.getId())))));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user