From 48f472d42ac604a57ceac4744ae50ae0a5e94e62 Mon Sep 17 00:00:00 2001 From: jourdiw Date: Fri, 3 Nov 2023 17:45:51 +0100 Subject: [PATCH] feat(service): add page reorder during update --- .../ApiUpdateDocumentationPageUsecase.java | 38 +++- .../spring/UsecaseSpringConfiguration.java | 6 +- ...ApiUpdateDocumentationPageUsecaseTest.java | 190 +++++++++++++++++- 3 files changed, 229 insertions(+), 5 deletions(-) diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecase.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecase.java index 39578ea4f6a..475a881806b 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecase.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecase.java @@ -22,6 +22,7 @@ import io.gravitee.apim.core.documentation.domain_service.HomepageDomainService; import io.gravitee.apim.core.documentation.domain_service.UpdateApiDocumentationDomainService; import io.gravitee.apim.core.documentation.model.Page; +import io.gravitee.apim.core.documentation.query_service.PageQueryService; import java.util.Date; import java.util.Objects; import lombok.Builder; @@ -33,19 +34,22 @@ public class ApiUpdateDocumentationPageUsecase { private final HomepageDomainService homepageDomainService; private final ApiCrudService apiCrudService; private final PageCrudService pageCrudService; + private final PageQueryService pageQueryService; public ApiUpdateDocumentationPageUsecase( UpdateApiDocumentationDomainService updateApiDocumentationDomainService, ApiDocumentationDomainService apiDocumentationDomainService, HomepageDomainService homepageDomainService, ApiCrudService apiCrudService, - PageCrudService pageCrudService + PageCrudService pageCrudService, + PageQueryService pageQueryService ) { this.updateApiDocumentationDomainService = updateApiDocumentationDomainService; this.apiDocumentationDomainService = apiDocumentationDomainService; this.homepageDomainService = homepageDomainService; this.apiCrudService = apiCrudService; this.pageCrudService = pageCrudService; + this.pageQueryService = pageQueryService; } public Output execute(Input input) { @@ -69,7 +73,6 @@ public Output execute(Input input) { newPage.updatedAt(new Date()); newPage.visibility(input.visibility); newPage.homepage(input.homepage); - // TODO: Implement order logic -- APIM-3077 newPage.order(input.order); var updatedPage = this.updateApiDocumentationDomainService.updatePage(newPage.build(), oldPage, input.auditInfo); @@ -78,6 +81,10 @@ public Output execute(Input input) { this.homepageDomainService.setPreviousHomepageToFalse(input.apiId, updatedPage.getId()); } + if (updatedPage.getOrder() != oldPage.getOrder()) { + this.updatePageOrders(oldPage.getOrder(), updatedPage, input.auditInfo); + } + return new Output(updatedPage); } @@ -94,4 +101,31 @@ public record Input( ) {} public record Output(Page page) {} + + private void updatePageOrders(int oldOrder, Page updatedPage, AuditInfo auditInfo) { + var newOrder = updatedPage.getOrder(); + var shouldMoveDown = newOrder < oldOrder; + var orderIncrement = shouldMoveDown ? 1 : -1; + + this.pageQueryService.searchByApiIdAndParentId(updatedPage.getReferenceId(), updatedPage.getParentId()) + .stream() + .filter(page -> !Objects.equals(page.getId(), updatedPage.getId())) + .filter(page -> + shouldMoveDown + ? this.toBeMovedDown(oldOrder, newOrder, page.getOrder()) + : this.toBeMovedUp(oldOrder, newOrder, page.getOrder()) + ) + .forEach(page -> { + var updatedOrder = page.getOrder() + orderIncrement; + this.updateApiDocumentationDomainService.updatePage(page.toBuilder().order(updatedOrder).build(), page, auditInfo); + }); + } + + private boolean toBeMovedUp(int oldOrder, int newOrder, int pageOrder) { + return oldOrder < pageOrder && pageOrder <= newOrder; + } + + private boolean toBeMovedDown(int oldOrder, int newOrder, int pageOrder) { + return newOrder <= pageOrder && pageOrder < oldOrder; + } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/spring/UsecaseSpringConfiguration.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/spring/UsecaseSpringConfiguration.java index 59d39ee2531..45d6be4f6e0 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/spring/UsecaseSpringConfiguration.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/spring/UsecaseSpringConfiguration.java @@ -129,14 +129,16 @@ public ApiUpdateDocumentationPageUsecase apiUpdateDocumentationPageUsecase( ApiDocumentationDomainService apiDocumentationDomainService, HomepageDomainService homepageDomainService, ApiCrudService apiCrudService, - PageCrudService pageCrudService + PageCrudService pageCrudService, + PageQueryService pageQueryService ) { return new ApiUpdateDocumentationPageUsecase( updateApiDocumentationDomainService, apiDocumentationDomainService, homepageDomainService, apiCrudService, - pageCrudService + pageCrudService, + pageQueryService ); } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecaseTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecaseTest.java index 61b428ecf53..0643bda3805 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecaseTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/documentation/usecase/ApiUpdateDocumentationPageUsecaseTest.java @@ -115,7 +115,8 @@ void setUp() { new ApiDocumentationDomainService(pageQueryService, new HtmlSanitizerImpl()), new HomepageDomainService(pageQueryService, pageCrudService), apiCrudService, - pageCrudService + pageCrudService, + pageQueryService ); } @@ -490,6 +491,193 @@ void should_throw_error_if_duplicate_name() { } } + @Nested + class UpdateOrderTests { + + Page page_0 = Page + .builder() + .id("page_0") + .name("0") + .type(Page.Type.MARKDOWN) + .referenceType(Page.ReferenceType.API) + .referenceId(API_ID) + .parentId(OLD_FOLDER_PAGE.getId()) + .updatedAt(DATE) + .order(0) + .build(); + Page page_1 = Page + .builder() + .id("page_1") + .name("1") + .type(Page.Type.MARKDOWN) + .referenceType(Page.ReferenceType.API) + .referenceId(API_ID) + .parentId(OLD_FOLDER_PAGE.getId()) + .updatedAt(DATE) + .order(1) + .build(); + Page page_2 = Page + .builder() + .id("page_2") + .name("2") + .type(Page.Type.FOLDER) + .referenceType(Page.ReferenceType.API) + .referenceId(API_ID) + .parentId(OLD_FOLDER_PAGE.getId()) + .updatedAt(DATE) + .order(2) + .build(); + Page page_3 = Page + .builder() + .id("page_3") + .name("3") + .type(Page.Type.MARKDOWN) + .referenceType(Page.ReferenceType.API) + .referenceId(API_ID) + .parentId(OLD_FOLDER_PAGE.getId()) + .updatedAt(DATE) + .order(3) + .build(); + Page page_4 = Page + .builder() + .id("page_4") + .name("4") + .type(Page.Type.MARKDOWN) + .referenceType(Page.ReferenceType.API) + .referenceId(API_ID) + .parentId(OLD_FOLDER_PAGE.getId()) + .updatedAt(DATE) + .order(4) + .build(); + + @BeforeEach + void setup() { + initApiServices(List.of(Api.builder().id(API_ID).build())); + initPageServices(List.of(OLD_FOLDER_PAGE, page_0, page_1, page_2, page_3, page_4)); + } + + @Test + void should_insert_new_page_with_lower_order() { + // Change page_3 order to 1 + var res = apiUpdateDocumentationPageUsecase.execute( + ApiUpdateDocumentationPageUsecase.Input + .builder() + .apiId(API_ID) + .pageId(page_3.getId()) + .order(1) + .visibility(page_3.getVisibility()) + .content(page_3.getContent()) + .name(page_3.getName()) + .homepage(false) + .auditInfo(AUDIT_INFO) + .build() + ); + + assertThat(res.page()).isNotNull().hasFieldOrPropertyWithValue("order", 1); + assertThat(pageCrudService.get(page_0.getId()).getOrder()).isEqualTo(0); + assertThat(pageCrudService.get(page_1.getId()).getOrder()).isEqualTo(2); + assertThat(pageCrudService.get(page_2.getId()).getOrder()).isEqualTo(3); + assertThat(pageCrudService.get(page_4.getId()).getOrder()).isEqualTo(4); + } + + @Test + void should_insert_new_page_with_higher_order() { + // Change page_1 order to 3 + var res = apiUpdateDocumentationPageUsecase.execute( + ApiUpdateDocumentationPageUsecase.Input + .builder() + .apiId(API_ID) + .pageId(page_1.getId()) + .order(3) + .visibility(page_1.getVisibility()) + .content(page_1.getContent()) + .name(page_1.getName()) + .homepage(false) + .auditInfo(AUDIT_INFO) + .build() + ); + + assertThat(res.page()).isNotNull().hasFieldOrPropertyWithValue("order", 3); + assertThat(pageCrudService.get(page_0.getId()).getOrder()).isEqualTo(0); + assertThat(pageCrudService.get(page_2.getId()).getOrder()).isEqualTo(1); + assertThat(pageCrudService.get(page_3.getId()).getOrder()).isEqualTo(2); + assertThat(pageCrudService.get(page_4.getId()).getOrder()).isEqualTo(4); + } + + @Test + void should_not_change_order_if_the_same() { + var res = apiUpdateDocumentationPageUsecase.execute( + ApiUpdateDocumentationPageUsecase.Input + .builder() + .apiId(API_ID) + .pageId(page_1.getId()) + .order(1) + .visibility(page_1.getVisibility()) + .content(page_1.getContent()) + .name(page_1.getName()) + .homepage(false) + .auditInfo(AUDIT_INFO) + .build() + ); + + assertThat(res.page()).isNotNull().hasFieldOrPropertyWithValue("order", 1); + assertThat(pageCrudService.get(page_0.getId()).getOrder()).isEqualTo(0); + assertThat(pageCrudService.get(page_2.getId()).getOrder()).isEqualTo(2); + assertThat(pageCrudService.get(page_3.getId()).getOrder()).isEqualTo(3); + assertThat(pageCrudService.get(page_4.getId()).getOrder()).isEqualTo(4); + } + + @Test + void should_update_with_very_high_order() { + // Change page_1 order to 9999 + var res = apiUpdateDocumentationPageUsecase.execute( + ApiUpdateDocumentationPageUsecase.Input + .builder() + .apiId(API_ID) + .pageId(page_1.getId()) + .order(9999) + .visibility(page_1.getVisibility()) + .content(page_1.getContent()) + .name(page_1.getName()) + .homepage(false) + .auditInfo(AUDIT_INFO) + .build() + ); + + assertThat(res.page()).isNotNull().hasFieldOrPropertyWithValue("order", 9999); + assertThat(pageCrudService.get(page_0.getId()).getOrder()).isEqualTo(0); + assertThat(pageCrudService.get(page_2.getId()).getOrder()).isEqualTo(1); + assertThat(pageCrudService.get(page_3.getId()).getOrder()).isEqualTo(2); + assertThat(pageCrudService.get(page_4.getId()).getOrder()).isEqualTo(3); + } + + @Test + void should_only_change_order_of_pages_with_same_parent() { + var pageWithDifferentParent = page_0.toBuilder().id("other-page").parentId(null).build(); + initPageServices(List.of(page_0, page_1, page_2, page_3, page_4, pageWithDifferentParent)); + var res = apiUpdateDocumentationPageUsecase.execute( + ApiUpdateDocumentationPageUsecase.Input + .builder() + .apiId(API_ID) + .pageId(pageWithDifferentParent.getId()) + .order(1) + .visibility(pageWithDifferentParent.getVisibility()) + .content(pageWithDifferentParent.getContent()) + .name(pageWithDifferentParent.getName()) + .homepage(false) + .auditInfo(AUDIT_INFO) + .build() + ); + + assertThat(res.page()).isNotNull().hasFieldOrPropertyWithValue("order", 1); + assertThat(pageCrudService.get(page_0.getId()).getOrder()).isEqualTo(0); + assertThat(pageCrudService.get(page_1.getId()).getOrder()).isEqualTo(1); + assertThat(pageCrudService.get(page_2.getId()).getOrder()).isEqualTo(2); + assertThat(pageCrudService.get(page_3.getId()).getOrder()).isEqualTo(3); + assertThat(pageCrudService.get(page_4.getId()).getOrder()).isEqualTo(4); + } + } + private void initPageServices(List pages) { pageQueryService.initWith(pages); pageCrudService.initWith(pages);