Publishing an application has been implemented by introducting publishedDsl field inside Layout. On Publish, for all pages in the application, for all layouts inside each page, the dsl json object is copied into the publishedDsl json object.

This commit is contained in:
Trisha Anand 2019-10-23 04:41:51 +00:00
parent f8dddb212f
commit d178b1c729
10 changed files with 143 additions and 12 deletions

View File

@ -2,10 +2,15 @@ package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url; import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Application;
import com.appsmith.server.dtos.ResponseDTO;
import com.appsmith.server.services.ApplicationService; import com.appsmith.server.services.ApplicationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController @RestController
@RequestMapping(Url.APPLICATION_URL) @RequestMapping(Url.APPLICATION_URL)
@ -14,4 +19,11 @@ public class ApplicationController extends BaseController<ApplicationService, Ap
public ApplicationController(ApplicationService service) { public ApplicationController(ApplicationService service) {
super(service); super(service);
} }
@PostMapping("/publish/{applicationId}")
public Mono<ResponseDTO<Application>> publish(@PathVariable String applicationId) {
return service.publish(applicationId)
.map(published -> new ResponseDTO<>(HttpStatus.OK.value(), published, null));
}
} }

View File

@ -36,14 +36,20 @@ public class LayoutController {
@GetMapping("/{layoutId}/pages/{pageId}") @GetMapping("/{layoutId}/pages/{pageId}")
public Mono<ResponseDTO<Layout>> getLayout(@PathVariable String pageId, @PathVariable String layoutId) { public Mono<ResponseDTO<Layout>> getLayout(@PathVariable String pageId, @PathVariable String layoutId) {
return service.getLayout(pageId, layoutId) return service.getLayout(pageId, layoutId, false)
.map(created -> new ResponseDTO<>(HttpStatus.CREATED.value(), created, null)); .map(created -> new ResponseDTO<>(HttpStatus.OK.value(), created, null));
} }
@PutMapping("/{layoutId}/pages/{pageId}") @PutMapping("/{layoutId}/pages/{pageId}")
public Mono<ResponseDTO<Layout>> updateLayout(@PathVariable String pageId, @PathVariable String layoutId, @RequestBody Layout layout) { public Mono<ResponseDTO<Layout>> updateLayout(@PathVariable String pageId, @PathVariable String layoutId, @RequestBody Layout layout) {
return service.updateLayout(pageId, layoutId, layout) return service.updateLayout(pageId, layoutId, layout)
.map(created -> new ResponseDTO<>(HttpStatus.CREATED.value(), created, null)); .map(created -> new ResponseDTO<>(HttpStatus.OK.value(), created, null));
}
@GetMapping("/{layoutId}/pages/{pageId}/view")
public Mono<ResponseDTO<Layout>> getLayoutView(@PathVariable String pageId, @PathVariable String layoutId) {
return service.getLayout(pageId, layoutId, true)
.map(created -> new ResponseDTO<>(HttpStatus.OK.value(), created, null));
} }
} }

View File

@ -13,7 +13,5 @@ public class ApplicationPage {
String id; String id;
String name;
Boolean isDefault; Boolean isDefault;
} }

View File

@ -1,5 +1,6 @@
package com.appsmith.server.domains; package com.appsmith.server.domains;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
@ -36,6 +37,7 @@ public abstract class BaseDomain implements Persistable<String> {
protected Boolean deleted = false; protected Boolean deleted = false;
@JsonIgnore
@Override @Override
public boolean isNew() { public boolean isNew() {
return this.getId() == null; return this.getId() == null;

View File

@ -1,5 +1,6 @@
package com.appsmith.server.domains; package com.appsmith.server.domains;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@ -14,5 +15,19 @@ public class Layout extends BaseDomain {
ScreenType screen; ScreenType screen;
@JsonIgnore
Boolean viewMode = false;
JSONObject dsl; JSONObject dsl;
@JsonIgnore
JSONObject publishedDsl;
/**
* If view mode, the dsl returned should be the publishedDSL, else if the edit mode is on (view mode = false)
* the dsl returned should be JSONObject dsl
*/
public JSONObject getDsl() {
return viewMode ? publishedDsl : dsl;
}
} }

View File

@ -1,6 +1,7 @@
package com.appsmith.server.services; package com.appsmith.server.services;
import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.Page;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
public interface ApplicationService extends CrudService<Application, String> { public interface ApplicationService extends CrudService<Application, String> {
@ -9,4 +10,9 @@ public interface ApplicationService extends CrudService<Application, String> {
Mono<Application> findByIdAndOrganizationId(String id, String organizationId); Mono<Application> findByIdAndOrganizationId(String id, String organizationId);
Mono<Application> findByName(String name); Mono<Application> findByName(String name);
Mono<Application> publish(String applicationId);
Mono<Application> addPageToApplication(String applicationId, Page page);
} }

View File

@ -1,12 +1,15 @@
package com.appsmith.server.services; package com.appsmith.server.services;
import com.appsmith.server.constants.AnalyticsEvents;
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.Layout;
import com.appsmith.server.domains.Page;
import com.appsmith.server.domains.User; import com.appsmith.server.domains.User;
import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.ApplicationRepository; import com.appsmith.server.repositories.ApplicationRepository;
import com.appsmith.server.repositories.PageRepository;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
@ -17,6 +20,8 @@ import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Scheduler;
import javax.validation.Validator; import javax.validation.Validator;
import java.util.ArrayList;
import java.util.List;
@Slf4j @Slf4j
@ -25,6 +30,10 @@ public class ApplicationServiceImpl extends BaseService<ApplicationRepository, A
private final SessionUserService sessionUserService; private final SessionUserService sessionUserService;
//Using PageRepository instead of PageService is because a cyclic dependency is introduced if PageService is used here.
//TODO : Solve for this across LayoutService, PageService and ApplicationService.
private final PageRepository pageRepository;
@Autowired @Autowired
public ApplicationServiceImpl(Scheduler scheduler, public ApplicationServiceImpl(Scheduler scheduler,
Validator validator, Validator validator,
@ -32,9 +41,11 @@ public class ApplicationServiceImpl extends BaseService<ApplicationRepository, A
ReactiveMongoTemplate reactiveMongoTemplate, ReactiveMongoTemplate reactiveMongoTemplate,
ApplicationRepository repository, ApplicationRepository repository,
AnalyticsService analyticsService, AnalyticsService analyticsService,
SessionUserService sessionUserService) { SessionUserService sessionUserService,
PageRepository pageRepository) {
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService); super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService);
this.sessionUserService = sessionUserService; this.sessionUserService = sessionUserService;
this.pageRepository = pageRepository;
} }
@Override @Override
@ -91,4 +102,78 @@ public class ApplicationServiceImpl extends BaseService<ApplicationRepository, A
public Mono<Application> findByName(String name) { public Mono<Application> findByName(String name) {
return repository.findByName(name); return repository.findByName(name);
} }
/**
* This function is called during page create in Page Service. It adds the newly created
* page to its ApplicationPages list.
* @param applicationId
* @param page
* @return Updated application
*/
@Override
public Mono<Application> addPageToApplication(String applicationId, Page page) {
Mono<Application> applicationMono = findById(applicationId);
return applicationMono
.map(application -> {
List<ApplicationPage> applicationPages = application.getPages();
if (applicationPages == null) {
applicationPages = new ArrayList<>();
}
ApplicationPage applicationPage = new ApplicationPage();
applicationPage.setId(page.getId());
applicationPages.add(applicationPage);
application.setPages(applicationPages);
return application;
})
.flatMap(repository::save);
}
/**
* This function walks through all the pages in the application. In each page, it walks through all the layouts.
* In a layout, dsl and publishedDsl JSONObjects exist. Publish function is responsible for copying the dsl into
* the publishedDsl.
* @param applicationId
* @return Application
*/
@Override
public Mono<Application> publish(String applicationId) {
Mono<Application> applicationMono = findById(applicationId)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, "application", applicationId)));
return applicationMono
//Return all the pages in the Application
.map(application -> application.getPages())
.flatMapMany(Flux::fromIterable)
//In each page, copy each layout's dsl to publishedDsl field
.flatMap(applicationPage -> {
return pageRepository
.findById(applicationPage.getId())
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, "page", applicationPage.getId())))
.map(page -> {
List<Layout> layoutList = page.getLayouts();
for (Layout layout : layoutList) {
layout.setPublishedDsl(layout.getDsl());
}
return page;
})
.flatMap(pageRepository::save);
})
.collectList()
//The only reason the following has been added to ensure that the DAG completes. If the following is missing,
//the previous flatMap responsible for editing the layouts doesn't execute.
.flatMap(pages -> {
List<ApplicationPage> pageIds = new ArrayList<>();
for (Page page : pages) {
ApplicationPage applicationPage = new ApplicationPage();
applicationPage.setId(page.getId());
pageIds.add(applicationPage);
}
return applicationMono.map(application -> {
application.setPages(pageIds);
return application;
});
});
}
} }

View File

@ -6,7 +6,7 @@ import reactor.core.publisher.Mono;
public interface LayoutService { public interface LayoutService {
Mono<Layout> createLayout(String pageId, Layout layout); Mono<Layout> createLayout(String pageId, Layout layout);
Mono<Layout> getLayout(String pageId, String layoutId); Mono<Layout> getLayout(String pageId, String layoutId, Boolean viewMode);
Mono<Layout> updateLayout(String pageId, String layoutId, Layout layout); Mono<Layout> updateLayout(String pageId, String layoutId, Layout layout);
} }

View File

@ -54,7 +54,7 @@ public class LayoutServiceImpl implements LayoutService {
} }
@Override @Override
public Mono<Layout> getLayout(String pageId, String layoutId) { public Mono<Layout> getLayout(String pageId, String layoutId, Boolean viewMode) {
return pageService.findByIdAndLayoutsId(pageId, layoutId) return pageService.findByIdAndLayoutsId(pageId, layoutId)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGEID + " or " + FieldName.LAYOUTID))) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGEID + " or " + FieldName.LAYOUTID)))
.flatMap(pageService::doesPageIdBelongToCurrentUserOrganization) .flatMap(pageService::doesPageIdBelongToCurrentUserOrganization)
@ -62,7 +62,9 @@ public class LayoutServiceImpl implements LayoutService {
.map(page -> { .map(page -> {
List<Layout> layoutList = page.getLayouts(); List<Layout> layoutList = page.getLayouts();
//Because the findByIdAndLayoutsId call returned non-empty result, we are guaranteed to find the layoutId here. //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(); Layout matchedLayout = layoutList.stream().filter(layout -> layout.getId().equals(layoutId)).findFirst().get();
matchedLayout.setViewMode(viewMode);
return matchedLayout;
}); });
} }

View File

@ -59,7 +59,12 @@ public class PageServiceImpl extends BaseService<PageRepository, Page, String> i
layoutList.add(createDefaultLayout()); layoutList.add(createDefaultLayout());
page.setLayouts(layoutList); page.setLayouts(layoutList);
} }
return super.create(page);
return super.create(page)
//After the page has been saved, update the application (save the page id inside the application)
.flatMap(savedPage ->
applicationService.addPageToApplication(savedPage.getApplicationId(), savedPage)
.thenReturn(savedPage));
} }