Skip to content

Commit

Permalink
#28896 Updating ENdpoint to to search Categories on the entire tree (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
freddyDOTCMS authored Jul 2, 2024
1 parent 54611c0 commit 6704bda
Show file tree
Hide file tree
Showing 9 changed files with 800 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -257,6 +258,7 @@ public final Response getChildren(@Context final HttpServletRequest httpRequest,
final Map<String, Object> 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,
Expand Down Expand Up @@ -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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<Category> getItems(final User user, final String filter, final int limit, final int offset,
final String orderby, final OrderDirection direction, final Map<String, Object> 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<Category> 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<Category> result = new PaginatedArrayList<>();
result.setTotalResults(categories.getTotalCount());

if (categories.getCategories()!= null) {
Expand All @@ -63,4 +96,50 @@ public PaginatedArrayList<Category> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,74 +290,4 @@ public abstract class CategoryFactory {
* @return List of Category filtered
*/
public abstract List<Category> 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);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Loading

0 comments on commit 6704bda

Please sign in to comment.