hunk.code_window:     @Autowired
       ObjectMapper objectMapper;
       /**
        * This routerFunction is required to map /public/** endpoints to the src/main/resources/public folder
        * This is to allow static resources to be served by the server. Couldn't find an easier way to do this,
        * hence using RouterFunctions to implement this feature.
        * <p>
  
hunk.labels: keep keep keep add keep keep keep keep keep
hunk.after_edit:     @Value("${spring.security.oauth2.client.registration.google.redirectUriTemplate}")
       private String oAuth2RedirectUri;
  
hunk.file_path: app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java
hunk.type: add
file: 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.WithUserDetails;
  import org.springframework.test.annotation.DirtiesContext;
  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
  @DirtiesContext
  public class LayoutServiceTest {
      @Autowired
      LayoutService layoutService;
  
      @Autowired
      ApplicationService applicationService;
  
      @Autowired
      PageService pageService;
  
      Mono<Layout> layoutMono;
  
      Mono<Application> applicationMono;
  
      @Before
      public void setup() {
          applicationMono = applicationService.findByName("LayoutServiceTest TestApplications");
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      public void createLayoutWithNullPageId() {
          Layout layout = new Layout();
          Mono<Layout> layoutMono = layoutService.createLayout(null, layout);
          StepVerifier
                  .create(layoutMono)
                  .expectErrorMatches(throwable -> throwable instanceof AppsmithException &&
                          throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.PAGE_ID)))
                  .verify();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      public void createLayoutWithInvalidPageID() {
          Layout layout = new Layout();
          String pageId = "Some random ID which can never be a page's ID";
          Mono<Layout> layoutMono = layoutService.createLayout(pageId, layout);
          StepVerifier
                  .create(layoutMono)
                  .expectErrorMatches(throwable -> throwable instanceof AppsmithException &&
                          throwable.getMessage().equals(AppsmithError.INVALID_PARAMETER.getMessage(FieldName.PAGE_ID)))
                  .verify();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      public void createValidLayout() {
          Layout testLayout = new Layout();
          JSONObject obj = new JSONObject();
          obj.put("key1", "value1");
          testLayout.setDsl(obj);
  
          Page testPage = new Page();
          testPage.setName("LayoutServiceTest createValidLayout Page");
          Mono<Page> 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.getDsl().equals(obj));
                  })
                  .verifyComplete();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      public void updateLayoutInvalidPageId() {
          Layout testLayout = new Layout();
          JSONObject obj = new JSONObject();
          obj.put("key", "value");
          testLayout.setDsl(obj);
          AtomicReference<String> pageId = new AtomicReference<>();
  
          Page testPage = new Page();
          testPage.setName("LayoutServiceTest updateLayoutInvalidPage");
          Mono<Page> 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.setDsl(obj);
  
          Mono<Layout> 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.PAGE_ID + " or " + FieldName.LAYOUT_ID)))
                  .verify();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      public void updateLayoutValidPageId() {
          Layout testLayout = new Layout();
          JSONObject obj = new JSONObject();
          obj.put("key", "value");
          testLayout.setDsl(obj);
  
          Page testPage = new Page();
          testPage.setName("validPageName");
          Page page = pageService
                  .findByName(testPage.getName())
                  .block();
  
          Layout startLayout = layoutService.createLayout(page.getId(), testLayout).block();
  
          Layout updateLayout = new Layout();
          JSONObject obj1 = new JSONObject();
          obj1.put("key1", "value-updated");
          updateLayout.setDsl(obj);
  
          Mono<Layout> updatedLayoutMono = layoutService.updateLayout(page.getId(), startLayout.getId(), updateLayout);
  
          StepVerifier
                  .create(updatedLayoutMono)
                  .assertNext(layout -> {
                      assertThat(layout).isNotNull();
                      assertThat(layout.getId()).isNotNull();
                      assertThat(layout.getDsl().equals(obj1));
                  })
                  .verifyComplete();
      }
  
      @After
      public void purgePages() {
          pageService.deleteAll();
      }
  }
  