From 07614d8980467d6008efb7c31ba55167961bab76 Mon Sep 17 00:00:00 2001 From: Trisha Anand Date: Wed, 11 Sep 2019 10:44:31 +0000 Subject: [PATCH] CRUD for pages and layouts. --- .../configurations/ClientUserRepository.java | 5 +- .../appsmith/server/constants/FieldName.java | 3 + .../com/appsmith/server/constants/Url.java | 1 + .../server/controllers/LayoutController.java | 37 +++- .../server/controllers/PageController.java | 21 ++ .../com/appsmith/server/domains/Page.java | 2 + .../server/exceptions/AppsmithError.java | 1 + .../repositories/ApplicationRepository.java | 9 + .../server/repositories/PageRepository.java | 14 ++ .../server/services/ApplicationService.java | 6 + .../services/ApplicationServiceImpl.java | 47 +++++ .../server/services/LayoutService.java | 8 +- .../server/services/LayoutServiceImpl.java | 98 +++++++-- .../services/OrganizationServiceImpl.java | 1 - .../appsmith/server/services/PageService.java | 19 ++ .../server/services/PageServiceImpl.java | 104 ++++++++++ .../services/ApplicationServiceTest.java | 120 +++++++++++ .../server/services/LayoutServiceTest.java | 194 ++++++++++++++++++ .../server/services/PageServiceTest.java | 99 +++++++++ 19 files changed, 769 insertions(+), 20 deletions(-) create mode 100644 app/server/src/main/java/com/appsmith/server/controllers/PageController.java create mode 100644 app/server/src/main/java/com/appsmith/server/repositories/PageRepository.java create mode 100644 app/server/src/main/java/com/appsmith/server/services/PageService.java create mode 100644 app/server/src/main/java/com/appsmith/server/services/PageServiceImpl.java create mode 100644 app/server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java create mode 100644 app/server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java create mode 100644 app/server/src/test/java/com/appsmith/server/services/PageServiceTest.java diff --git a/app/server/src/main/java/com/appsmith/server/configurations/ClientUserRepository.java b/app/server/src/main/java/com/appsmith/server/configurations/ClientUserRepository.java index 748327269f..4bbeb325d7 100644 --- a/app/server/src/main/java/com/appsmith/server/configurations/ClientUserRepository.java +++ b/app/server/src/main/java/com/appsmith/server/configurations/ClientUserRepository.java @@ -7,7 +7,6 @@ import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.services.OrganizationService; import com.appsmith.server.services.UserService; -import org.springframework.context.annotation.Configuration; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; @@ -84,10 +83,10 @@ public class ClientUserRepository implements ServerOAuth2AuthorizedClientReposit // Check if the list of configured custom domains match the authenticated principal. // This is to provide more control over which accounts can be used to access the application. // TODO: This is not a good way to do this. Ideally, we should pass "hd=example.com" to OAuth2 provider to list relevant accounts only - if(!commonConfig.getAllowedDomains().isEmpty()) { + if (!commonConfig.getAllowedDomains().isEmpty()) { DefaultOidcUser userPrincipal = (DefaultOidcUser) principal.getPrincipal(); String domain = (String) userPrincipal.getAttributes().getOrDefault("hd", ""); - if(!commonConfig.getAllowedDomains().contains(domain)) { + if (!commonConfig.getAllowedDomains().contains(domain)) { return Mono.error(new AppsmithException(AppsmithError.UNAUTHORIZED_DOMAIN)); } } diff --git a/app/server/src/main/java/com/appsmith/server/constants/FieldName.java b/app/server/src/main/java/com/appsmith/server/constants/FieldName.java index 1ab278a58a..a56944dfd4 100644 --- a/app/server/src/main/java/com/appsmith/server/constants/FieldName.java +++ b/app/server/src/main/java/com/appsmith/server/constants/FieldName.java @@ -4,4 +4,7 @@ public class FieldName { public static String ORGANIZATION = "organization"; public static String ID = "id"; public static String NAME = "name"; + public static String PAGEID = "pageId"; + public static String LAYOUTID = "layoutId"; + public static String APPLICATIONID = "applicationId"; } diff --git a/app/server/src/main/java/com/appsmith/server/constants/Url.java b/app/server/src/main/java/com/appsmith/server/constants/Url.java index 2df17b743f..89764ffef8 100644 --- a/app/server/src/main/java/com/appsmith/server/constants/Url.java +++ b/app/server/src/main/java/com/appsmith/server/constants/Url.java @@ -13,4 +13,5 @@ public interface Url { String ACTION_URL = BASE_URL + VERSION + "/actions"; String USER_URL = BASE_URL + VERSION + "/users"; String APPLICATION_URL = BASE_URL + VERSION + "/applications"; + String PAGE_URL = BASE_URL + VERSION + "/pages"; } diff --git a/app/server/src/main/java/com/appsmith/server/controllers/LayoutController.java b/app/server/src/main/java/com/appsmith/server/controllers/LayoutController.java index 8b893f6bd2..23163c6429 100644 --- a/app/server/src/main/java/com/appsmith/server/controllers/LayoutController.java +++ b/app/server/src/main/java/com/appsmith/server/controllers/LayoutController.java @@ -2,17 +2,48 @@ package com.appsmith.server.controllers; import com.appsmith.server.constants.Url; import com.appsmith.server.domains.Layout; +import com.appsmith.server.dtos.ResponseDto; import com.appsmith.server.services.LayoutService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +import javax.validation.Valid; @RestController @RequestMapping(Url.LAYOUT_URL) -public class LayoutController extends BaseController { +public class LayoutController { + + private final LayoutService service; @Autowired - public LayoutController(LayoutService service) { - super(service); + public LayoutController(LayoutService layoutService) { + this.service = layoutService; } + + @PostMapping("/pages/{pageId}") + public Mono> createLayout(@PathVariable String pageId, @Valid @RequestBody Layout layout) { + return service.createLayout(pageId, layout) + .map(created -> new ResponseDto<>(HttpStatus.CREATED.value(), created, null)); + } + + @GetMapping("/{layoutId}/pages/{pageId}") + public Mono> getLayout(@PathVariable String pageId, @PathVariable String layoutId) { + return service.getLayout(pageId, layoutId) + .map(created -> new ResponseDto<>(HttpStatus.CREATED.value(), created, null)); + } + + @PutMapping("/{layoutId}/pages/{pageId}") + public Mono> updateLayout(@PathVariable String pageId, @PathVariable String layoutId, @RequestBody Layout layout) { + return service.updateLayout(pageId, layoutId, layout) + .map(created -> new ResponseDto<>(HttpStatus.CREATED.value(), created, null)); + } + } diff --git a/app/server/src/main/java/com/appsmith/server/controllers/PageController.java b/app/server/src/main/java/com/appsmith/server/controllers/PageController.java new file mode 100644 index 0000000000..166004ae07 --- /dev/null +++ b/app/server/src/main/java/com/appsmith/server/controllers/PageController.java @@ -0,0 +1,21 @@ +package com.appsmith.server.controllers; + +import com.appsmith.server.constants.Url; +import com.appsmith.server.domains.Page; +import com.appsmith.server.services.PageService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(Url.PAGE_URL) +@Slf4j +public class PageController extends BaseController { + + @Autowired + public PageController(PageService service) { + super(service); + } + +} diff --git a/app/server/src/main/java/com/appsmith/server/domains/Page.java b/app/server/src/main/java/com/appsmith/server/domains/Page.java index 47bfcffae7..cbf9b29a57 100644 --- a/app/server/src/main/java/com/appsmith/server/domains/Page.java +++ b/app/server/src/main/java/com/appsmith/server/domains/Page.java @@ -6,6 +6,7 @@ import lombok.Setter; import lombok.ToString; import org.springframework.data.mongodb.core.mapping.Document; +import javax.validation.constraints.NotNull; import java.util.List; @Getter @@ -16,6 +17,7 @@ import java.util.List; public class Page extends BaseDomain { String name; + @NotNull String applicationId; List layouts; diff --git a/app/server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java b/app/server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java index b337b17ab1..a5768681f2 100644 --- a/app/server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java +++ b/app/server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java @@ -12,6 +12,7 @@ public enum AppsmithError { PLUGIN_NOT_INSTALLED(400, 4001, "Plugin {0} not installed"), PLUGIN_ID_NOT_GIVEN(400, 4002, "Missing plugin id. Please input correct plugin id"), RESOURCE_ID_NOT_GIVEN(400, 4003, "Missing resource id. Please input correct resource id"), + PAGE_DOESNT_BELONG_TO_USER_ORGANIZATION(400, 4006, "Page {0} does not belong to the current user {1} organization."), UNAUTHORIZED_DOMAIN(401, 4001, "Invalid email domain provided. Please sign in with a valid work email ID"), INTERNAL_SERVER_ERROR(500, 5000, "Internal server error while processing request"); diff --git a/app/server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java b/app/server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java index b8ccb16812..9f83d30bad 100644 --- a/app/server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java +++ b/app/server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java @@ -2,7 +2,16 @@ package com.appsmith.server.repositories; import com.appsmith.server.domains.Application; import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; @Repository public interface ApplicationRepository extends BaseRepository { + Flux findByOrganizationId(String orgId); + + Mono findByIdAndOrganizationId(String id, String orgId); + + Mono findById(String id); + + Mono findByName(String name); } diff --git a/app/server/src/main/java/com/appsmith/server/repositories/PageRepository.java b/app/server/src/main/java/com/appsmith/server/repositories/PageRepository.java new file mode 100644 index 0000000000..ceddec1f64 --- /dev/null +++ b/app/server/src/main/java/com/appsmith/server/repositories/PageRepository.java @@ -0,0 +1,14 @@ +package com.appsmith.server.repositories; + +import com.appsmith.server.domains.Page; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Mono; + +@Repository +public interface PageRepository extends BaseRepository { + Mono findByIdAndLayoutsId(String id, String layoutId); + + Mono findByName(String name); + + Mono deleteAll(); +} diff --git a/app/server/src/main/java/com/appsmith/server/services/ApplicationService.java b/app/server/src/main/java/com/appsmith/server/services/ApplicationService.java index edb2b719be..712b91dcf1 100644 --- a/app/server/src/main/java/com/appsmith/server/services/ApplicationService.java +++ b/app/server/src/main/java/com/appsmith/server/services/ApplicationService.java @@ -1,6 +1,12 @@ package com.appsmith.server.services; import com.appsmith.server.domains.Application; +import reactor.core.publisher.Mono; public interface ApplicationService extends CrudService { + Mono findById(String id); + + Mono findByIdAndOrganizationId(String id, String organizationId); + + Mono findByName(String name); } diff --git a/app/server/src/main/java/com/appsmith/server/services/ApplicationServiceImpl.java b/app/server/src/main/java/com/appsmith/server/services/ApplicationServiceImpl.java index ffd4c1c403..1714ac3165 100644 --- a/app/server/src/main/java/com/appsmith/server/services/ApplicationServiceImpl.java +++ b/app/server/src/main/java/com/appsmith/server/services/ApplicationServiceImpl.java @@ -1,18 +1,23 @@ package com.appsmith.server.services; +import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; 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 lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; import javax.validation.Validator; + @Slf4j @Service public class ApplicationServiceImpl extends BaseService implements ApplicationService { @@ -27,6 +32,10 @@ public class ApplicationServiceImpl extends BaseService create(Application application) { + if (application.getName() == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.NAME)); + } + Mono userMono = userService.getCurrentUser(); return userMono @@ -37,4 +46,42 @@ public class ApplicationServiceImpl extends BaseService get() { + Mono userMono = userService.getCurrentUser(); + + return userMono + .map(user -> user.getOrganizationId()) + .flatMapMany(orgId -> repository.findByOrganizationId(orgId)); + } + + @Override + public Mono getById(String id) { + if (id == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); + } + + Mono userMono = userService.getCurrentUser(); + + return userMono + .map(user -> user.getOrganizationId()) + .flatMap(orgId -> repository.findByIdAndOrganizationId(id, orgId)) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, "resource", id))); + } + + @Override + public Mono findById(String id) { + return repository.findById(id); + } + + @Override + public Mono findByIdAndOrganizationId(String id, String organizationId) { + return repository.findByIdAndOrganizationId(id, organizationId); + } + + @Override + public Mono findByName(String name) { + return repository.findByName(name); + } } diff --git a/app/server/src/main/java/com/appsmith/server/services/LayoutService.java b/app/server/src/main/java/com/appsmith/server/services/LayoutService.java index 39e2331501..5153c358b2 100644 --- a/app/server/src/main/java/com/appsmith/server/services/LayoutService.java +++ b/app/server/src/main/java/com/appsmith/server/services/LayoutService.java @@ -1,6 +1,12 @@ package com.appsmith.server.services; import com.appsmith.server.domains.Layout; +import reactor.core.publisher.Mono; -public interface LayoutService extends CrudService { +public interface LayoutService { + Mono createLayout(String pageId, Layout layout); + + Mono getLayout(String pageId, String layoutId); + + Mono updateLayout(String pageId, String layoutId, Layout layout); } diff --git a/app/server/src/main/java/com/appsmith/server/services/LayoutServiceImpl.java b/app/server/src/main/java/com/appsmith/server/services/LayoutServiceImpl.java index ed974d954f..c3af0c7417 100644 --- a/app/server/src/main/java/com/appsmith/server/services/LayoutServiceImpl.java +++ b/app/server/src/main/java/com/appsmith/server/services/LayoutServiceImpl.java @@ -1,26 +1,100 @@ package com.appsmith.server.services; +import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Layout; -import com.appsmith.server.repositories.LayoutRepository; +import com.appsmith.server.domains.Page; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; import lombok.extern.slf4j.Slf4j; +import org.bson.types.ObjectId; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.ReactiveMongoTemplate; -import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.stereotype.Service; -import reactor.core.scheduler.Scheduler; +import reactor.core.publisher.Mono; -import javax.validation.Validator; +import java.util.ArrayList; +import java.util.List; @Slf4j @Service -public class LayoutServiceImpl extends BaseService implements LayoutService { +public class LayoutServiceImpl implements LayoutService { + + private final PageService pageService; @Autowired - public LayoutServiceImpl(Scheduler scheduler, - Validator validator, - MongoConverter mongoConverter, - ReactiveMongoTemplate reactiveMongoTemplate, - LayoutRepository repository) { - super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository); + public LayoutServiceImpl(PageService pageService) { + this.pageService = pageService; + } + + @Override + public Mono createLayout(String pageId, Layout layout) { + if (pageId == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGEID)); + } + + Mono pageMono = pageService + .findById(pageId) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGEID))); + + return pageMono + .map(page -> { + List layoutList = page.getLayouts(); + if (layoutList == null) { + //no layouts exist for this page + layoutList = new ArrayList(); + } + //Adding an Id to the layout to ensure that a layout can be referred to by its ID as well. + layout.setId(new ObjectId().toString()); + layoutList.add(layout); + page.setLayouts(layoutList); + return page; + }) + .flatMap(pageService::save) + .then(Mono.just(layout)); + } + + @Override + public Mono getLayout(String pageId, String layoutId) { + return pageService.findByIdAndLayoutsId(pageId, layoutId) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGEID + " or " + FieldName.LAYOUTID))) + .flatMap(pageService::doesPageIdBelongToCurrentUserOrganization) + //The pageId given is correct and belongs to the current user's organization. + .map(page -> { + List layoutList = page.getLayouts(); + //Because the findByIdAndLayoutsId call returned non-empty result, we are guaranteed to find the layoutId here. + return layoutList.stream().filter(layout -> layout.getId().equals(layoutId)).findFirst().get(); + }); + } + + @Override + public Mono updateLayout(String pageId, String layoutId, Layout layout) { + return pageService.findByIdAndLayoutsId(pageId, layoutId) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGEID + " or " + FieldName.LAYOUTID))) + .flatMap(pageService::doesPageIdBelongToCurrentUserOrganization) + //The pageId given is correct and belongs to the current user's organization. + .map(page -> { + List layoutList = page.getLayouts(); + //Because the findByIdAndLayoutsId call returned non-empty result, we are guaranteed to find the layoutId here. + for (Layout storedLayout : layoutList) { + if (storedLayout.getId().equals(layoutId)) { + BeanUtils.copyProperties(layout, storedLayout); + storedLayout.setId(layoutId); + break; + } + } + page.setLayouts(layoutList); + return page; + }) + .flatMap(pageService::save) + .flatMap(page -> { + List layoutList = page.getLayouts(); + for (Layout storedLayout : layoutList) { + if (storedLayout.getId().equals(layoutId)) { + return Mono.just(storedLayout); + } + } + return Mono.empty(); + }); } } + diff --git a/app/server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java b/app/server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java index f3915a23d9..2cf183cb2b 100644 --- a/app/server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java +++ b/app/server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java @@ -56,7 +56,6 @@ public class OrganizationServiceImpl extends BaseService { + + Mono findById(String pageId); + + Mono save(Page page); + + Mono findByIdAndLayoutsId(String pageId, String layoutId); + + Mono doesPageIdBelongToCurrentUserOrganization(Page page); + + Mono findByName(String name); + + Mono deleteAll(); +} diff --git a/app/server/src/main/java/com/appsmith/server/services/PageServiceImpl.java b/app/server/src/main/java/com/appsmith/server/services/PageServiceImpl.java new file mode 100644 index 0000000000..ed702029df --- /dev/null +++ b/app/server/src/main/java/com/appsmith/server/services/PageServiceImpl.java @@ -0,0 +1,104 @@ +package com.appsmith.server.services; + +import com.appsmith.server.constants.FieldName; +import com.appsmith.server.domains.Layout; +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.PageRepository; +import lombok.extern.slf4j.Slf4j; +import org.bson.types.ObjectId; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.data.mongodb.core.convert.MongoConverter; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Scheduler; + +import javax.validation.Validator; +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class PageServiceImpl extends BaseService implements PageService { + + private final UserService userService; + private final ApplicationService applicationService; + + @Autowired + public PageServiceImpl(Scheduler scheduler, Validator validator, MongoConverter mongoConverter, ReactiveMongoTemplate reactiveMongoTemplate, PageRepository repository, UserService userService, ApplicationService applicationService) { + super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository); + this.userService = userService; + this.applicationService = applicationService; + } + + @Override + public Mono create(Page page) { + if (page.getId() != null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); + } else if (page.getName() == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.NAME)); + } else if (page.getApplicationId() == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.APPLICATIONID)); + } + List layoutList = page.getLayouts(); + if (layoutList == null) { + layoutList = new ArrayList<>(); + } + if (layoutList.isEmpty()) { + layoutList.add(createDefaultLayout()); + page.setLayouts(layoutList); + } + return repository.save(page); + } + + + @Override + public Mono findById(String pageId) { + return repository.findById(pageId); + } + + @Override + public Mono save(Page page) { + return repository.save(page); + } + + @Override + public Mono findByIdAndLayoutsId(String pageId, String layoutId) { + return repository.findByIdAndLayoutsId(pageId, layoutId); + } + + @Override + public Mono doesPageIdBelongToCurrentUserOrganization(Page page) { + Mono userMono = userService.getCurrentUser(); + final String[] username = {null}; + + return userMono + .map(user -> { + username[0] = user.getEmail(); + return user; + }) + .flatMap(user -> applicationService.findByIdAndOrganizationId(page.getApplicationId(), user.getOrganizationId())) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.PAGE_DOESNT_BELONG_TO_USER_ORGANIZATION, page.getId(), username[0]))) + //If mono transmits, then application id belongs to the current user's organization. Return page. + .then(Mono.just(page)); + } + + @Override + public Mono findByName(String name) { + return repository.findByName(name); + } + + private Layout createDefaultLayout() { + Layout layout = new Layout(); + layout.setId(new ObjectId().toString()); + return layout; + } + + @Override + public Mono deleteAll() { + return repository.deleteAll(); + } +} diff --git a/app/server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java b/app/server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java new file mode 100644 index 0000000000..d994c3538f --- /dev/null +++ b/app/server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java @@ -0,0 +1,120 @@ +package com.appsmith.server.services; + +import com.appsmith.server.constants.FieldName; +import com.appsmith.server.domains.Application; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Slf4j +public class ApplicationServiceTest { + + @Autowired + ApplicationService applicationService; + + @Test + @WithMockUser(username = "api_user") + public void createApplicationWithNullName() { + Application application = new Application(); + Mono applicationMono = Mono.just(application) + .flatMap(applicationService::create); + StepVerifier + .create(applicationMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.NAME))) + .verify(); + } + + @Test + @WithMockUser(username = "api_user") + public void createValidApplication() { + Application testApplication = new Application(); + testApplication.setName("ApplicationServiceTest TestApp"); + Mono applicationMono = applicationService.create(testApplication); + + StepVerifier + .create(applicationMono) + .assertNext(application -> { + assertThat(application).isNotNull(); + assertThat(application.getId()).isNotNull(); + assertThat(application.getName().equals("ApplicationServiceTest TestApp")); + }) + .verifyComplete(); + } + + /* Tests for Get Application Flow */ + + @Test + public void getApplicationInvalidId() { + Mono applicationMono = applicationService.getById("random-id"); + StepVerifier.create(applicationMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.NO_RESOURCE_FOUND.getMessage("resource", "random-id"))) + .verify(); + } + + @Test + public void getApplicationNullId() { + Mono applicationMono = applicationService.getById(null); + StepVerifier.create(applicationMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.ID))) + .verify(); + } + + @Test + @WithMockUser(username = "api_user") + public void validGetApplicationByName() { + Application application = new Application(); + application.setName("validGetApplicationByName-Test"); + Mono createApplication = applicationService.create(application); + Mono getApplication = createApplication.flatMap(t -> applicationService.getById(t.getId())); + StepVerifier.create(getApplication) + .assertNext(t -> { + assertThat(t).isNotNull(); + assertThat(t.getId()).isNotNull(); + assertThat(t.getName()).isEqualTo("validGetApplicationByName-Test"); + }) + .verifyComplete(); + } + + /* Tests for Update Application Flow */ + @Test + @WithMockUser(username = "api_user") + public void validUpdateApplication() { + Application application = new Application(); + application.setName("validUpdateApplication-Test"); + + Mono createApplication = + applicationService + .create(application); + Mono updateApplication = createApplication + .map(t -> { + t.setName("NewValidUpdateApplication-Test"); + return t; + }) + .flatMap(t -> applicationService.update(t.getId(), t)) + .flatMap(t -> applicationService.getById(t.getId())); + + StepVerifier.create(updateApplication) + .assertNext(t -> { + assertThat(t).isNotNull(); + assertThat(t.getId()).isNotNull(); + assertThat(t.getName()).isEqualTo("NewValidUpdateApplication-Test"); + }) + .verifyComplete(); + } + +} diff --git a/app/server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java b/app/server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java new file mode 100644 index 0000000000..89e47ce23d --- /dev/null +++ b/app/server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java @@ -0,0 +1,194 @@ +package com.appsmith.server.services; + +import com.appsmith.server.constants.FieldName; +import com.appsmith.server.domains.Application; +import com.appsmith.server.domains.Layout; +import com.appsmith.server.domains.Page; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; +import lombok.extern.slf4j.Slf4j; +import net.minidev.json.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.concurrent.atomic.AtomicReference; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Slf4j +public class LayoutServiceTest { + @Autowired + LayoutService layoutService; + + @Autowired + ApplicationService applicationService; + + @Autowired + PageService pageService; + + Mono layoutMono; + + Mono applicationMono; + + @Before + @WithMockUser(username = "api_user") + public void setup() { + + Application testApplication = new Application(); + testApplication.setName("LayoutServiceTest TestApplications"); + applicationMono = + applicationService.findByName(testApplication.getName()) + .switchIfEmpty(applicationService.create(testApplication)); + + } + + @Test + @WithMockUser(username = "api_user") + public void createLayoutWithNullPageId() { + Layout layout = new Layout(); + Mono layoutMono = layoutService.createLayout(null, layout); + StepVerifier + .create(layoutMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.PAGEID))) + .verify(); + } + + @Test + @WithMockUser(username = "api_user") + public void createLayoutWithInvalidPageID() { + Layout layout = new Layout(); + String pageId = "Some random ID which can never be a page's ID"; + Mono layoutMono = layoutService.createLayout(pageId, layout); + StepVerifier + .create(layoutMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.PAGEID))) + .verify(); + } + + @Test + @WithMockUser(username = "api_user") + public void createValidLayout() { + Layout testLayout = new Layout(); + JSONObject obj = new JSONObject(); + obj.put("key1", "value1"); + testLayout.setData(obj); + + Page testPage = new Page(); + testPage.setName("LayoutServiceTest createValidLayout Page"); + Mono pageMono = pageService + .findByName(testPage.getName()) + .switchIfEmpty(applicationMono + .map(application -> { + testPage.setApplicationId(application.getId()); + return testPage; + }) + .flatMap(pageService::save)); + layoutMono = pageMono + .flatMap(page -> layoutService.createLayout(page.getId(), testLayout)); + + StepVerifier + .create(layoutMono) + .assertNext(layout -> { + assertThat(layout).isNotNull(); + assertThat(layout.getId()).isNotNull(); + assertThat(layout.getData().equals(obj)); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(username = "api_user") + public void updateLayoutInvalidPageId() { + Layout testLayout = new Layout(); + JSONObject obj = new JSONObject(); + obj.put("key", "value"); + testLayout.setData(obj); + AtomicReference pageId = new AtomicReference<>(); + + Page testPage = new Page(); + testPage.setName("LayoutServiceTest updateLayoutInvalidPage"); + Mono pageMono = pageService + .findByName(testPage.getName()) + .switchIfEmpty(applicationMono + .map(application -> { + testPage.setApplicationId(application.getId()); + return testPage; + }) + .flatMap(pageService::save)); + + Layout startLayout = pageMono + .flatMap(page -> { + pageId.set(page.getId()); + return layoutService.createLayout(page.getId(), testLayout); + }).block(); + + Layout updateLayout = new Layout(); + obj = new JSONObject(); + obj.put("key", "value-updated"); + updateLayout.setData(obj); + + Mono updatedLayoutMono = layoutService.updateLayout("random-impossible-id-page", startLayout.getId(), updateLayout); + + StepVerifier + .create(updatedLayoutMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.PAGEID + " or " + FieldName.LAYOUTID))) + .verify(); + } + + @Test + @WithMockUser(username = "api_user") + public void updateLayoutValidPageId() { + Layout testLayout = new Layout(); + JSONObject obj = new JSONObject(); + obj.put("key", "value"); + testLayout.setData(obj); + + Page testPage = new Page(); + testPage.setName("LayoutServiceTest updateLayoutValidPage"); + Page page = pageService + .findByName(testPage.getName()) + .switchIfEmpty(applicationMono + .map(application -> { + testPage.setApplicationId(application.getId()); + return testPage; + }) + .flatMap(pageService::save)) + .block(); + + Layout startLayout = layoutService.createLayout(page.getId(), testLayout).block(); + + Layout updateLayout = new Layout(); + JSONObject obj1 = new JSONObject(); + obj1.put("key1", "value-updated"); + updateLayout.setData(obj); + + Mono updatedLayoutMono = layoutService.updateLayout(page.getId(), startLayout.getId(), updateLayout); + + StepVerifier + .create(updatedLayoutMono) + .assertNext(layout -> { + assertThat(layout).isNotNull(); + assertThat(layout.getId()).isNotNull(); + assertThat(layout.getData().equals(obj1)); + }) + .verifyComplete(); + } + + @After + public void purgePages() { + pageService.deleteAll(); + } +} diff --git a/app/server/src/test/java/com/appsmith/server/services/PageServiceTest.java b/app/server/src/test/java/com/appsmith/server/services/PageServiceTest.java new file mode 100644 index 0000000000..6787330a9f --- /dev/null +++ b/app/server/src/test/java/com/appsmith/server/services/PageServiceTest.java @@ -0,0 +1,99 @@ +package com.appsmith.server.services; + +import com.appsmith.server.constants.FieldName; +import com.appsmith.server.domains.Application; +import com.appsmith.server.domains.Page; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Slf4j +public class PageServiceTest { + @Autowired + PageService pageService; + + @Autowired + ApplicationService applicationService; + + Mono applicationMono; + + @Before + @WithMockUser(username = "api_user") + public void setup() { + purgeAllPages(); + Application application = new Application(); + application.setName("PageAPI-Test-Application"); + applicationMono = applicationService.create(application); + } + + @Test + @WithMockUser(username = "api_user") + public void createPageWithNullName() { + Page page = new Page(); + Mono pageMono = Mono.just(page) + .flatMap(pageService::create); + StepVerifier + .create(pageMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.NAME))) + .verify(); + } + + @Test + @WithMockUser(username = "api_user") + public void createPageWithNullApplication() { + Page page = new Page(); + page.setName("Page without application"); + Mono pageMono = Mono.just(page) + .flatMap(pageService::create); + StepVerifier + .create(pageMono) + .expectErrorMatches(throwable -> throwable instanceof AppsmithException && + throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.APPLICATIONID))) + .verify(); + } + + @Test + @WithMockUser(username = "api_user") + public void createValidPage() { + Page testPage = new Page(); + testPage.setName("PageServiceTest TestApp"); + + Mono pageMono = applicationMono + .map(application -> { + testPage.setApplicationId(application.getOrganizationId()); + return testPage; + }) + .flatMap(pageService::create); + + StepVerifier + .create(pageMono) + .assertNext(page -> { + assertThat(page).isNotNull(); + assertThat(page.getId()).isNotNull(); + assertThat("PageServiceTest TestApp".equals(page.getName())); + + }) + .verifyComplete(); + } + + @After + public void purgeAllPages() { + pageService.deleteAll(); + } + +}