From 6704bdac4adc603a6c40bfd08f74b547aee1f4d5 Mon Sep 17 00:00:00 2001 From: freddyDOTCMS <147462678+freddyDOTCMS@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:30:11 -0600 Subject: [PATCH] #28896 Updating ENdpoint to to search Categories on the entire tree (#29091) ### Proposed Changes * Include a new parameter on the category/children Endpoint, to look through the Entire tree https://github.com/dotCMS/core/pull/29091/files#diff-1677f12a3b6c8909f3436afc7817819af2f46ac5ae6a37bdfab43690ffa24780R242 *Include this parameter on the paginator also https://github.com/dotCMS/core/pull/29091/files#diff-693f0b4479466ce339fe60e74bc320dc80aa8ce835d8e6fd661b32bdba348419R67 --- .../api/v1/categories/CategoriesResource.java | 6 +- .../util/pagination/CategoriesPaginator.java | 97 ++- .../categories/business/CategoryAPI.java | 2 +- .../categories/business/CategoryAPIImpl.java | 2 +- .../categories/business/CategoryFactory.java | 70 -- .../business/CategorySearchCriteria.java | 99 +++ .../categories/business/CategoryAPITest.java | 14 +- .../business/CategoryFactoryTest.java | 14 +- .../postman/Category.postman_collection.json | 608 +++++++++++++++++- 9 files changed, 800 insertions(+), 112 deletions(-) create mode 100644 dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategorySearchCriteria.java diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/categories/CategoriesResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/categories/CategoriesResource.java index de84f9fc4593..33b2f33ce41c 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/categories/CategoriesResource.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/categories/CategoriesResource.java @@ -238,7 +238,8 @@ public final Response getChildren(@Context final HttpServletRequest httpRequest, @DefaultValue("category_name") @QueryParam(PaginationUtil.ORDER_BY) final String orderBy, @DefaultValue("ASC") @QueryParam(PaginationUtil.DIRECTION) final String direction, @QueryParam("inode") final String inode, - @QueryParam("showChildrenCount") final boolean showChildrenCount) throws DotDataException, DotSecurityException { + @QueryParam("showChildrenCount") final boolean showChildrenCount, + @QueryParam("allLevels") final boolean allLevels) throws DotDataException, DotSecurityException { final InitDataObject initData = webResource.init(null, httpRequest, httpResponse, true, null); @@ -257,6 +258,7 @@ public final Response getChildren(@Context final HttpServletRequest httpRequest, final Map extraParams = new HashMap<>(); extraParams.put("inode", inode); extraParams.put("childrenCategories", true); + extraParams.put("searchInAllLevels", allLevels); try { response = showChildrenCount == false ? this.paginationUtil.getPage(httpRequest, user, filter, page, perPage, orderBy, @@ -463,7 +465,7 @@ public final Response save(@Context final HttpServletRequest httpRequest, : this.getChildren(httpRequest, httpResponse, categoryEditForm.getFilter(), categoryEditForm.getPage(), categoryEditForm.getPerPage(), "", categoryEditForm.getDirection(), - categoryEditForm.getParentInode(), true); + categoryEditForm.getParentInode(), true, false); } /** diff --git a/dotCMS/src/main/java/com/dotcms/util/pagination/CategoriesPaginator.java b/dotCMS/src/main/java/com/dotcms/util/pagination/CategoriesPaginator.java index a606feec76ed..64ead7ec759c 100644 --- a/dotCMS/src/main/java/com/dotcms/util/pagination/CategoriesPaginator.java +++ b/dotCMS/src/main/java/com/dotcms/util/pagination/CategoriesPaginator.java @@ -1,5 +1,7 @@ package com.dotcms.util.pagination; +import com.dotmarketing.portlets.categories.business.CategoryFactory; +import com.dotmarketing.portlets.categories.business.CategorySearchCriteria; import com.liferay.util.StringPool; import java.util.Collection; import java.util.List; @@ -33,25 +35,56 @@ public CategoriesPaginator(){ this(APILocator.getCategoryAPI()); } + /** + * + * Returns a {@link Category} by pagination. You can set three parameters to customize the search: + * - searchInAllLevels: A Boolean value. + * If TRUE, the search will include categories at any level, ignoring the childrenCategories parameter. + * - childrenCategories: A Boolean value. + * If FALSE, the search is limited to the top-level category. + * If TRUE, the search is confined to the children of the category specified by the inode parameter. + * -inode: If it is set and childrenCategories is TRUE, the search is limited to the children of the category with this inode + * If it is set searchInAllLevels is TRUE, the search starts at this category and goes through its children recursively . + * + * @param user The {@link User} that is using this method. + * @param filter Allows you to add more conditions to the query via SQL code. It's very + * important that you always sanitize the code in order to avoid SQL + * injection attacks. The complexity of the allows SQL code will depend on + * how the Paginator class is implemented. + * @param limit The maximum number of returned items in the result set, for pagination + * purposes. + * @param offset The requested page number of the result set, for pagination purposes. + * @param orderby The order-by clause, which must always be sanitized as well. + * @param direction The direction of the order-by clause for the results. + * @param extraParams A {@link Map} including any extra parameters that may be required by the + * implementation class that are not part of this method's signature. + * + * @return + */ @Override public PaginatedArrayList getItems(final User user, final String filter, final int limit, final int offset, final String orderby, final OrderDirection direction, final Map extraParams) { boolean childrenCategories = extraParams.containsKey("childrenCategories") ? (Boolean)extraParams.get("childrenCategories") : false; + boolean searchInAllLevels = extraParams.containsKey("searchInAllLevels") ? (Boolean)extraParams.get("searchInAllLevels") : false; + String inode = extraParams.containsKey("inode") ? String.valueOf(extraParams.get("inode")) : StringPool.BLANK; try { - String categoriesSort = null; - if (orderby != null) { - categoriesSort = direction == OrderDirection.DESC ? "-" + orderby : orderby; - } + final CategorySearchCriteria searchingCriteria = new CategorySearchCriteria.Builder() + .filter(filter) + .limit(limit) + .offset(offset) + .orderBy(orderby != null ? orderby : "category_name") + .direction(direction != null ? direction : OrderDirection.ASC ) + .rootInode(inode) + .build(); - final PaginatedArrayList result = new PaginatedArrayList<>(); - final PaginatedCategories categories = childrenCategories == false ? - categoryAPI.findTopLevelCategories(user, false, offset, limit, filter, categoriesSort) - : categoryAPI.findChildren(user, extraParams.containsKey("inode") ? String.valueOf(extraParams.get("inode")) : StringPool.BLANK, - false, offset, limit, filter, categoriesSort); + final PaginatedCategories categories = searchInAllLevels ? searchAllLevels(user, searchingCriteria) : + searchInOneLevel(user, searchingCriteria, childrenCategories); + + final PaginatedArrayList result = new PaginatedArrayList<>(); result.setTotalResults(categories.getTotalCount()); if (categories.getCategories()!= null) { @@ -63,4 +96,50 @@ public PaginatedArrayList getItems(final User user, final String filte throw new DotRuntimeException(e); } } + + /** + * Search for categories at every level. + * + * @param user to check Permission + * @param searchingCriteria Criteria for Searching + * @return + * @throws DotDataException + * @throws DotSecurityException + */ + private PaginatedCategories searchAllLevels(final User user, + final CategorySearchCriteria searchingCriteria) + throws DotDataException, DotSecurityException { + + return categoryAPI.findAll(searchingCriteria, user, false); + } + + /** + * Search for a category at a single level. This could be either the top level or within the immediate children of any category. + * + * @param user to Check permission + * @param searchingCriteria Search Criteria + + * @return + * @throws DotDataException + * @throws DotSecurityException + */ + private PaginatedCategories searchInOneLevel(final User user, + final CategorySearchCriteria searchingCriteria, + final boolean childrenCategories) + throws DotDataException, DotSecurityException { + + String categoriesSort = null; + + if (searchingCriteria.getOrderBy() != null) { + categoriesSort = searchingCriteria.getDirection() == OrderDirection.DESC + ? "-" + searchingCriteria.getOrderBy() : searchingCriteria.getOrderBy(); + } + + return childrenCategories == false ? + categoryAPI.findTopLevelCategories(user, false, searchingCriteria.getOffset(), + searchingCriteria.getLimit(), searchingCriteria.getFilter(), categoriesSort) : + categoryAPI.findChildren(user, searchingCriteria.getRootInode(), false, + searchingCriteria.getOffset(), searchingCriteria.getLimit(), searchingCriteria.getFilter(), + categoriesSort); + } } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPI.java b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPI.java index 2989f3835799..4159ddcad20f 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPI.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPI.java @@ -494,7 +494,7 @@ Category findByVariable(final String variable, final User user, * * @return List of Category filtered */ - PaginatedCategories findAll(final CategoryFactory.CategorySearchCriteria searchCriteria, + PaginatedCategories findAll(final CategorySearchCriteria searchCriteria, final User user, boolean respectFrontendRoles) throws DotDataException, DotSecurityException; } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPIImpl.java b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPIImpl.java index 729012cc08bb..3bddeb99206c 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPIImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryAPIImpl.java @@ -962,7 +962,7 @@ private boolean hasCategoryFields(final ContentType contentType) { */ @CloseDBIfOpened @Override - public PaginatedCategories findAll(final CategoryFactory.CategorySearchCriteria searchCriteria, + public PaginatedCategories findAll(final CategorySearchCriteria searchCriteria, final User user, boolean respectFrontendRoles) throws DotDataException, DotSecurityException { diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryFactory.java b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryFactory.java index 51345ef673bd..760933dea817 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryFactory.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategoryFactory.java @@ -290,74 +290,4 @@ public abstract class CategoryFactory { * @return List of Category filtered */ public abstract List findAll(final CategorySearchCriteria searchCriteria) throws DotDataException; - - /** - * Represents Search Criteria for {@link Category} searching, you cans set the follow: - * - * - filter: Value used to filter the Category by, returning only Categories that contain this value in their key, name, or variable name. - * - inode: Entry point on the Category tree to start the searching. - * - orderBy: Field name to order the Category - * - direction: Order by direction, it can be 'ASC' or 'DESC' - */ - public static class CategorySearchCriteria { - final String rootInode; - final String filter; - final String orderBy; - final OrderDirection direction; - final int limit; - final int offset; - private CategorySearchCriteria (final Builder builder) { - this.rootInode = builder.rootInode; - this.filter = builder.filter; - this.orderBy = builder.orderBy; - this.direction = builder.direction; - this.limit = builder.limit; - this.offset = builder.offset; - } - - public static class Builder { - private String rootInode; - private String filter; - private String orderBy = "category_name"; - private OrderDirection direction = OrderDirection.ASC; - private int limit = -1; - private int offset = 0; - - public Builder rootInode(String rootInode) { - this.rootInode = rootInode; - return this; - } - - public Builder filter(String filter) { - this.filter = filter; - return this; - } - - public Builder orderBy(String orderBy) { - this.orderBy = orderBy; - return this; - } - - public Builder direction(OrderDirection direction) { - this.direction = direction; - return this; - } - - public Builder limit(int limit) { - this.limit = limit; - return this; - } - - public Builder offset(int offset) { - this.offset = offset; - return this; - } - - - public CategorySearchCriteria build() { - return new CategorySearchCriteria(this); - } - } - } - } diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategorySearchCriteria.java b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategorySearchCriteria.java new file mode 100644 index 000000000000..b0271b478697 --- /dev/null +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/categories/business/CategorySearchCriteria.java @@ -0,0 +1,99 @@ +package com.dotmarketing.portlets.categories.business; + +import com.dotcms.util.pagination.OrderDirection; +import com.dotmarketing.portlets.categories.model.Category; + +/** + * Represents Search Criteria for {@link Category} searching, you cans set the follow: + * + * - filter: Value used to filter the Category by, returning only Categories that contain this value in their key, name, or variable name. + * - inode: Entry point on the Category tree to start the searching. + * - orderBy: Field name to order the Category + * - direction: Order by direction, it can be 'ASC' or 'DESC' + * - rootInode: If the root inode is set, the search will be conducted only among the children of this category. + * Otherwise, the search will include only the top-level categories. + */ +public class CategorySearchCriteria { + final String rootInode; + final String filter; + final String orderBy; + final OrderDirection direction; + final int limit; + final int offset; + private CategorySearchCriteria (final Builder builder) { + this.rootInode = builder.rootInode; + this.filter = builder.filter; + this.orderBy = builder.orderBy; + this.direction = builder.direction; + this.limit = builder.limit; + this.offset = builder.offset; + } + + public String getRootInode() { + return rootInode; + } + + public String getFilter() { + return filter; + } + + public String getOrderBy() { + return orderBy; + } + + public OrderDirection getDirection() { + return direction; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public static class Builder { + private String rootInode; + private String filter; + private String orderBy = "category_name"; + private OrderDirection direction = OrderDirection.ASC; + private int limit = -1; + private int offset = 0; + + public Builder rootInode(String rootInode) { + this.rootInode = rootInode; + return this; + } + + public Builder filter(String filter) { + this.filter = filter; + return this; + } + + public Builder orderBy(String orderBy) { + this.orderBy = orderBy; + return this; + } + + public Builder direction(OrderDirection direction) { + this.direction = direction; + return this; + } + + public Builder limit(int limit) { + this.limit = limit; + return this; + } + + public Builder offset(int offset) { + this.offset = offset; + return this; + } + + + public CategorySearchCriteria build() { + return new CategorySearchCriteria(this); + } + } +} diff --git a/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryAPITest.java b/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryAPITest.java index 40a8563221aa..5898d24dbb42 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryAPITest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryAPITest.java @@ -1548,7 +1548,7 @@ public void test_save_createTopLevelCategory_asLimitedUser_fail() * Method to test: {@link CategoryAPIImpl#findAll(CategoryFactory.CategorySearchCriteria, User, boolean)} * When: Call the API method * Should: it should - * - Use the {@link CategoryFactoryImpl#findAll(CategoryFactory.CategorySearchCriteria)} to search the {@link Category} + * - Use the {@link CategoryFactoryImpl#findAll(CategorySearchCriteria)} to search the {@link Category} * - Use the {@link PermissionAPI#filterCollection(List, int, boolean, User)} method to check permission */ @Test @@ -1557,8 +1557,7 @@ public void getAllCategoriesFiltered() throws DotDataException, DotSecurityExcep final String filter = new RandomString().nextString(); final String orderBy = "category_key"; - final CategoryFactory.CategorySearchCriteria searchingCriteria = - new CategoryFactory.CategorySearchCriteria.Builder() + final CategorySearchCriteria searchingCriteria = new CategorySearchCriteria.Builder() .rootInode(inode) .direction(OrderDirection.DESC) .orderBy(orderBy) @@ -1590,7 +1589,7 @@ public void getAllCategoriesFiltered() throws DotDataException, DotSecurityExcep } /** - * Method to test: {@link CategoryAPIImpl#findAll(CategoryFactory.CategorySearchCriteria, User, boolean)} + * Method to test: {@link CategoryAPIImpl#findAll(CategorySearchCriteria, User, boolean)} * When: Create 9 Category, call the two times: * first: limit =5, offset =0 * second: limit =5, offset =5 @@ -1603,8 +1602,8 @@ public void getAllCategoriesFilteredWithPagination() throws DotDataException, Do final String filter = new RandomString().nextString(); final String orderBy = "category_key"; - final CategoryFactory.CategorySearchCriteria searchingCriteria_1 = - new CategoryFactory.CategorySearchCriteria.Builder() + final CategorySearchCriteria searchingCriteria_1 = + new CategorySearchCriteria.Builder() .rootInode(inode) .direction(OrderDirection.DESC) .orderBy(orderBy) @@ -1613,8 +1612,7 @@ public void getAllCategoriesFilteredWithPagination() throws DotDataException, Do .offset(0) .build(); - final CategoryFactory.CategorySearchCriteria searchingCriteria_2 = - new CategoryFactory.CategorySearchCriteria.Builder() + final CategorySearchCriteria searchingCriteria_2 = new CategorySearchCriteria.Builder() .rootInode(inode) .direction(OrderDirection.DESC) .orderBy(orderBy) diff --git a/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryFactoryTest.java b/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryFactoryTest.java index adaa4bb53349..70de9fbd6083 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryFactoryTest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/portlets/categories/business/CategoryFactoryTest.java @@ -404,7 +404,7 @@ public void getAllCategoriesFiltered(final FilterTestCase filterTestCase) throws List categoriesExpected = list(childCategory_1, childCategory_2, childCategory_3, grandchildCategory_1, grandchildCategory_2, childCategory_6, childCategory_7).stream().map(Category::getInode).collect(Collectors.toList()); - final CategoryFactory.CategorySearchCriteria categorySearchCriteria = new CategoryFactory.CategorySearchCriteria.Builder() + final CategorySearchCriteria categorySearchCriteria = new CategorySearchCriteria.Builder() .filter(filterTestCase.transformToSearch()) .rootInode(topLevelCategory_1.getInode()) .build(); @@ -416,7 +416,7 @@ public void getAllCategoriesFiltered(final FilterTestCase filterTestCase) throws } /** - * Method to test: {@link CategoryFactoryImpl#findAll(CategoryFactory.CategorySearchCriteria)} + * Method to test: {@link CategoryFactoryImpl#findAll(CategorySearchCriteria)} * When: call the method with filter and inode equals to null * Should: return all the Categories * @@ -447,7 +447,7 @@ public void getAllCategoriesWithNullFilterAndInode() throws DotDataException { .parent(childCategory_2) .nextPersisted(); - final CategoryFactory.CategorySearchCriteria categorySearchCriteria = new CategoryFactory.CategorySearchCriteria.Builder() + final CategorySearchCriteria categorySearchCriteria = new CategorySearchCriteria.Builder() .build(); final Collection categoriesWithFilter = FactoryLocator.getCategoryFactory().findAll(categorySearchCriteria); @@ -457,7 +457,7 @@ public void getAllCategoriesWithNullFilterAndInode() throws DotDataException { } /** - * Method to test: {@link CategoryFactoryImpl#findAll(CategoryFactory.CategorySearchCriteria)} + * Method to test: {@link CategoryFactoryImpl#findAll(CategorySearchCriteria)} * When: call the method with filter equals to null and inode not null * Should: return all children Categories * @@ -517,7 +517,7 @@ public void getAllCategoriesWithNullFilter() throws DotDataException { .parent(topLevelCategory_2) .nextPersisted(); - final CategoryFactory.CategorySearchCriteria categorySearchCriteria = new CategoryFactory.CategorySearchCriteria.Builder() + final CategorySearchCriteria categorySearchCriteria = new CategorySearchCriteria.Builder() .rootInode(topLevelCategory_1.getInode()) .build(); @@ -531,7 +531,7 @@ public void getAllCategoriesWithNullFilter() throws DotDataException { } /** - * Method to test: {@link CategoryFactoryImpl#findAll(CategoryFactory.CategorySearchCriteria)} + * Method to test: {@link CategoryFactoryImpl#findAll(CategorySearchCriteria)} * When: Create a set of {@link Category} and called the method ordering by key * Should: return all children Categories ordered * @@ -562,7 +562,7 @@ public void getAllCategoriesFilteredOrdered() throws DotDataException { .parent(childCategory_2) .nextPersisted(); - final CategoryFactory.CategorySearchCriteria categorySearchCriteria = new CategoryFactory.CategorySearchCriteria.Builder() + final CategorySearchCriteria categorySearchCriteria = new CategorySearchCriteria.Builder() .orderBy("category_key") .direction(OrderDirection.ASC) .rootInode(topLevelCategory_1.getInode()) diff --git a/dotcms-postman/src/main/resources/postman/Category.postman_collection.json b/dotcms-postman/src/main/resources/postman/Category.postman_collection.json index a3095cb162e0..3bdd253c5448 100644 --- a/dotcms-postman/src/main/resources/postman/Category.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Category.postman_collection.json @@ -1,8 +1,9 @@ { "info": { - "_postman_id": "cd61fd14-c09a-45be-8d96-1759b1e0b294", + "_postman_id": "6101d86a-acc3-42d5-a3cb-266d9c1e7a72", "name": "Category", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "30436704" }, "item": [ { @@ -1421,12 +1422,7 @@ "type": "file", "src": "/home/hmb-g8/Desktop/categories_10_6_2022.csv" } - ], - "options": { - "raw": { - "language": "json" - } - } + ] }, "url": { "raw": "{{serverURL}}/api/v1/categories/_import", @@ -1514,12 +1510,7 @@ "type": "file", "src": "/home/hmb-g8/Desktop/categories_10_6_2022.csv" } - ], - "options": { - "raw": { - "language": "json" - } - } + ] }, "url": { "raw": "{{serverURL}}/api/v1/categories/_import", @@ -2467,6 +2458,587 @@ } ] }, + { + "name": "Getting Category Children", + "item": [ + { + "name": "Create Top Level category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"Information Saved Correctly\", function () {", + " ", + " pm.expect(jsonData.entity.categoryName).to.eql(\"PostmanTest Top level Category\");", + "});", + "", + "pm.collectionVariables.set(\"topCategoryInode\", jsonData.entity.inode);", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\":\"PostmanTest TOP_LEVEL\",\n \"categoryName\" : \"PostmanTest Top level Category\",\n \"categoryVelocityVarName\" : \"PostmanTest_childrenTopLevel\",\n \"sortOrder\" : 1\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/categories", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories" + ] + } + }, + "response": [] + }, + { + "name": "Create First child Category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"Information Saved Correctly\", function () {", + " ", + " pm.expect(jsonData.entity.categoryName).to.eql(\"PostmanTest Child 1\");", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\":\"PostmanTest Child 1\",\n \"categoryName\" : \"PostmanTest Child 1\",\n \"keywords\":\"This is a child test category\",\n \"categoryVelocityVarName\" : \"PostmanTest_ChildTestKey_1\",\n \"parent\" : \"{{topCategoryInode}}\"\n}\n\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/categories", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories" + ] + } + }, + "response": [] + }, + { + "name": "Create Second child Category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"Information Saved Correctly\", function () {", + " ", + " pm.expect(jsonData.entity.categoryName).to.eql(\"PostmanTest Child 2\");", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\":\"PostmanTest Child 2\",\n \"categoryName\" : \"PostmanTest Child 2\",\n \"keywords\":\"This is a child test category\",\n \"categoryVelocityVarName\" : \"PostmanTest_ChildTestKey_2\",\n \"parent\" : \"{{topCategoryInode}}\"\n}\n\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/categories", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories" + ] + } + }, + "response": [] + }, + { + "name": "Create Third child Category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"Information Saved Correctly\", function () {", + " ", + " pm.expect(jsonData.entity.categoryName).to.eql(\"Child 3\");", + "});", + "", + "", + "pm.collectionVariables.set(\"child3Inode\", jsonData.entity.inode);" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\":\"Child 3\",\n \"categoryName\" : \"Child 3\",\n \"keywords\":\"This is a child test category\",\n \"categoryVelocityVarName\" : \"ChildTestKey_3\",\n \"parent\" : \"{{topCategoryInode}}\"\n}\n\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/categories", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories" + ] + } + }, + "response": [] + }, + { + "name": "Create Grandchild Category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"Information Saved Correctly\", function () {", + " ", + " pm.expect(jsonData.entity.categoryName).to.eql(\"PostmanTest Grandchild 1\");", + "});", + "", + "", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\":\"PostmanTest ChiGrandchildld 1\",\n \"categoryName\" : \"PostmanTest Grandchild 1\",\n \"keywords\":\"This is a child test category\",\n \"categoryVelocityVarName\" : \"PostmanTest_GrandcßhildTestKey_1\",\n \"parent\" : \"{{child3Inode}}\"\n}\n\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/categories", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories" + ] + } + }, + "response": [] + }, + { + "name": "Create Second Top Level category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\":\"Second TOP_LEVEL\",\n \"categoryName\" : \"Top level Category\",\n \"categoryVelocityVarName\" : \"second_childrenTopLevel\",\n \"sortOrder\" : 1\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/categories", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories" + ] + } + }, + "response": [] + }, + { + "name": "Get categories by filter AND looking on the entire tree", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"Fetch successfully without errors\", function () {", + " pm.expect(jsonData.errors).to.have.lengthOf(0);", + "});", + "", + "pm.expect(3).to.have.equals(jsonData.entity.length);", + "", + "pm.test('get the right categories', () => { ", + " let data = [];", + "", + " for (let i = 0; i < jsonData.entity.length; i++)", + " { ", + " data.push(jsonData.entity[i]['categoryName']); ", + " }", + "", + " data.includes(\"PostmanTest Child 1\");", + " data.includes(\"PostmanTest Child 2\");", + " data.includes(\"PostmanTest Grandchild 1\");", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/categories/children?filter=PostmanTest&allLevels=true&inode={{topCategoryInode}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories", + "children" + ], + "query": [ + { + "key": "filter", + "value": "PostmanTest" + }, + { + "key": "allLevels", + "value": "true" + }, + { + "key": "inode", + "value": "{{topCategoryInode}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Get categories by filter AND looking just in children", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code should be ok 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"Fetch successfully without errors\", function () {", + " pm.expect(jsonData.errors).to.have.lengthOf(0);", + "});", + "", + "pm.expect(2).to.have.equals(jsonData.entity.length);", + "", + "pm.test('get the right categories', () => { ", + " let data = [];", + "", + " for (let i = 0; i < jsonData.entity.length; i++)", + " { ", + " data.push(jsonData.entity[i]['categoryName']); ", + " }", + "", + " data.includes(\"PostmanTest Child 1\");", + " data.includes(\"PostmanTest Child 2\");", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/categories/children?filter=PostmanTest&inode={{topCategoryInode}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "categories", + "children" + ], + "query": [ + { + "key": "filter", + "value": "PostmanTest" + }, + { + "key": "inode", + "value": "{{topCategoryInode}}" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "if (!pm.environment.get('jwt')) {", + " const serverURL = pm.environment.get('serverURL'); // Get the server URL from the environment variable", + " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", + "", + " if (!pm.environment.get('jwt')) {", + " const username = 'admin@dotcms.com';", + " const password = 'admin';", + " const basicAuth = btoa(`${username}:${password}`);", + "", + " const requestOptions = {", + " url: apiUrl,", + " method: \"POST\",", + " header: {", + " \"accept\": \"*/*\",", + " \"content-type\": \"application/json\",", + " \"Authorization\": `Basic ${basicAuth}`", + " },", + " body: {", + " mode: \"raw\",", + " raw: JSON.stringify({", + " \"expirationSeconds\": 7200,", + " \"userId\": \"dotcms.org.1\",", + " \"network\": \"0.0.0.0/0\",", + " \"claims\": {\"label\": \"postman-tests\"}", + " })", + " }", + " };", + "", + " pm.sendRequest(requestOptions, function (err, response) {", + " if (err) {", + " console.log(err);", + " } else {", + " const jwt = response.json().entity.jwt;", + " pm.environment.set('jwt', jwt);", + " }", + " });", + " }", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ] + }, { "name": "Create New Category without parent", "event": [ @@ -4807,6 +5379,14 @@ { "key": "categoryKey", "value": "" + }, + { + "key": "topCategoryInode", + "value": "" + }, + { + "key": "child3Inode", + "value": "" } ] } \ No newline at end of file