Skip to content

Commit

Permalink
#28896 Including listParents as attribute on the response of the chil… (
Browse files Browse the repository at this point in the history
  • Loading branch information
freddyDOTCMS authored Jul 3, 2024
1 parent dcfa034 commit a33cb02
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,6 @@ Category findByVariable(final String variable, final User user,
*
* @return List of Category filtered
*/
PaginatedCategories findAll(final CategorySearchCriteria searchCriteria,
final User user, boolean respectFrontendRoles)
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 @@ -970,7 +970,9 @@ public PaginatedCategories findAll(final CategorySearchCriteria searchCriteria,
throw new IllegalArgumentException("Limit must be greater than 0");
}

final List<Category> categories = permissionAPI.filterCollection(categoryFactory.findAll(searchCriteria),
final List<Category> allCategories = new ArrayList<>(categoryFactory.findAll(searchCriteria));

final List<Category> categories = permissionAPI.filterCollection(allCategories,
PermissionAPI.PERMISSION_READ, respectFrontendRoles, user);

return getCategoriesSubList(searchCriteria.offset, searchCriteria.limit, categories, null);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package com.dotmarketing.portlets.categories.business;

import java.util.Collection;

import java.util.List;

import com.dotcms.util.PaginationUtil;
import com.dotcms.util.pagination.OrderDirection;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.portlets.categories.model.Category;
import com.liferay.portal.model.User;
import com.dotmarketing.portlets.categories.model.HierarchedCategory;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.QueryParam;

/**
*
Expand Down Expand Up @@ -287,7 +283,7 @@ public abstract class CategoryFactory {
*
* @param searchCriteria Search Criteria
*
* @return List of Category filtered
* @return List of Category filteredx
*/
public abstract List<Category> findAll(final CategorySearchCriteria searchCriteria) throws DotDataException;
public abstract List<HierarchedCategory> findAll(final CategorySearchCriteria searchCriteria) throws DotDataException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.dotcms.util.CloseUtils;
import com.dotcms.util.DotPreconditions;
import com.dotcms.util.JsonUtil;
import com.dotcms.util.ReflectionUtils;
import com.dotmarketing.beans.Tree;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.CacheLocator;
Expand All @@ -17,12 +19,15 @@
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.factories.TreeFactory;
import com.dotmarketing.portlets.categories.model.Category;
import com.dotmarketing.portlets.categories.model.HierarchedCategory;
import com.dotmarketing.portlets.categories.model.ShortCategory;
import com.dotmarketing.util.InodeUtils;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.dotmarketing.util.VelocityUtil;
import com.liferay.util.StringPool;

import java.io.IOException;
import java.io.Serializable;
import java.sql.*;
import java.util.ArrayList;
Expand All @@ -40,6 +45,7 @@
*/
public class CategoryFactoryImpl extends CategoryFactory {

public static final String INODE = "inode";
CategoryCache catCache;
final CategorySQL categorySQL;

Expand Down Expand Up @@ -602,21 +608,59 @@ protected List<Category> findTopLevelCategoriesByFilter(String filter, String so
* @param sqlResults sql query results
* @return a list of categories objects
*/
List<Category> convertForCategories(final List<Map<String, Object>> sqlResults) {

List<Category> convertForCategories(final List<Map<String, Object>> sqlResults) {
List<Category> categories = new ArrayList<>();

if ( sqlResults != null ) {

for ( Map<String, Object> row : sqlResults ) {
Category category = convertForCategory(row);
Category category = convertForCategory(row, Category.class);
categories.add(category);
}
}

return categories;
}

private List<HierarchedCategory> convertForHierarchedCategories(final List<Map<String, Object>> sqlResults) {
List<HierarchedCategory> categories = new ArrayList<>();

if ( sqlResults != null ) {

for ( Map<String, Object> row : sqlResults ) {
HierarchedCategory category = (HierarchedCategory) convertForCategory(row, HierarchedCategory.class);

try {
if (row !=null && row.get("path") != null ) {
final String parentsASJsonArray = "[" + row.get("path") + "]";

final List<ShortCategory> parentList = ((List<Map<String, String>>) JsonUtil.getObjectFromJson(parentsASJsonArray, List.class))
.stream()
.map(map -> new ShortCategory.Builder()
.setCategoryName(map.get("categoryName"))
.setKey(map.get("key"))
.setInode(map.get(INODE))
.build()
)
.collect(Collectors.toList());

category.setParentList(parentList.subList(0, parentList.size() - 1));
}

categories.add(category);
} catch (IOException e) {
Logger.warn(CategoryFactoryImpl.class, e::getMessage);
}
}
}

return categories;
}

private Category convertForCategory(final Map<String, Object> sqlResult) {
return convertForCategory(sqlResult, Category.class);
}

/**
* Converts the category information coming from the database into a {@link Category}
* object with all of its properties. If the information is not present, a
Expand All @@ -625,15 +669,15 @@ List<Category> convertForCategories(final List<Map<String, Object>> sqlResults)
* @param sqlResult - The data of a specific category from the database.
* @return The {@link Category} object.
*/
private Category convertForCategory(final Map<String, Object> sqlResult) {
private Category convertForCategory(final Map<String, Object> sqlResult, Class<? extends Category> clazz) {

Category category = null;
if ( sqlResult != null ) {
category = new Category();
category = ReflectionUtils.newInstance(clazz);

Object sortOrder = sqlResult.get("sort_order");

category.setInode((String) sqlResult.get("inode"));
category.setInode((String) sqlResult.get(INODE));
category.setCategoryName((String) sqlResult.get("category_name"));
category.setKey((String) sqlResult.get("category_key"));
if ( sortOrder != null ) {
Expand Down Expand Up @@ -805,7 +849,7 @@ public void sortChildren(final String inode) throws DotDataException {
private void putResultInCatCache( final ResultSet rs ) throws SQLException, DotDataException {
while(rs.next()) {
// calling find will put it into cache internally
find(rs.getString("inode"));
find(rs.getString(INODE));
}
}

Expand Down Expand Up @@ -841,11 +885,11 @@ protected String suggestVelocityVarName(final String categoryVelVarName) throws
* @return
* @throws DotDataException
*/
public List<Category> findAll(final CategorySearchCriteria searchCriteria)
public List<HierarchedCategory> findAll(final CategorySearchCriteria searchCriteria)
throws DotDataException {

if (!UtilMethods.isSet(searchCriteria.rootInode) && !UtilMethods.isSet(searchCriteria.filter)) {
return findAll();
if (searchCriteria.rootInode == null) {
throw new IllegalArgumentException();
}

final String query = getFindAllSQLQuery(searchCriteria);
Expand All @@ -862,22 +906,26 @@ public List<Category> findAll(final CategorySearchCriteria searchCriteria)
dc.addObject("%" + searchCriteria.filter.toLowerCase() + "%");
}

final List<Category> categories = convertForCategories(UtilMethods.isSet(searchCriteria.rootInode) ?
final List<Map<String, Object>> results = UtilMethods.isSet(searchCriteria.rootInode) ?
dc.loadObjectResults().stream()
.filter(map -> !map.get("inode").equals(searchCriteria.rootInode))
.collect(Collectors.toList()) : dc.loadObjectResults());
.filter(map -> !map.get(INODE).equals(searchCriteria.rootInode))
.collect(Collectors.toList()) : dc.loadObjectResults();

final List<HierarchedCategory> categories = convertForHierarchedCategories(results);

updateCache(categories);
return categories;
}

private static String getFindAllSQLQuery(CategorySearchCriteria searchCriteria) {
final String queryTemplate = "WITH RECURSIVE CategoryHierarchy AS ( " +
"SELECT c.* FROM Category c %s " +
"SELECT c.*, json_build_object('inode', inode, 'categoryName', category_name, 'key', category_key)::varchar AS path " +
"FROM Category c %s " +
"UNION ALL " +
"SELECT c.* FROM Category c JOIN tree t ON c.inode = t.child JOIN CategoryHierarchy ch ON t.parent = ch.inode " +
"SELECT c.*, CONCAT(ch.path, ',', json_build_object('inode', c.inode, 'categoryName', c.category_name, 'key', c.category_key)::varchar) AS path " +
"FROM Category c JOIN tree t ON c.inode = t.child JOIN CategoryHierarchy ch ON t.parent = ch.inode " +
") " +
"SELECT * FROM CategoryHierarchy %s ORDER BY %s %s";
"SELECT distinct *,path FROM CategoryHierarchy %s ORDER BY %s %s";

final String rootCategoryFilter = UtilMethods.isSet(searchCriteria.rootInode) ? "WHERE c.inode = ?" : StringPool.BLANK;

Expand All @@ -886,12 +934,11 @@ private static String getFindAllSQLQuery(CategorySearchCriteria searchCriteria)
"LOWER(category_key) LIKE ? OR " +
"LOWER(category_velocity_var_name) LIKE ?" : StringPool.BLANK;

final String query = String.format(queryTemplate, rootCategoryFilter, filterCategories, searchCriteria.orderBy,
return String.format(queryTemplate, rootCategoryFilter, filterCategories, searchCriteria.orderBy,
searchCriteria.direction.toString());
return query;
}

private void updateCache(List<Category> categories) throws DotDataException {
private void updateCache(List<? extends Category> categories) throws DotDataException {
for(final Category category : categories) {
if(catCache.get(category.getInode()) == null)
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.liferay.portal.model.User;
import org.apache.commons.lang.builder.ToStringBuilder;

import javax.ws.rs.NotSupportedException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
Expand Down Expand Up @@ -267,5 +268,4 @@ public ManifestInfo getManifestInfo() {
.title(this.getCategoryName())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.dotmarketing.portlets.categories.model;

import java.util.List;
import java.util.Objects;

/**
* Represents a {@link Category} with its hierarchy calculated.
* This means traversing from the current category all the way up to the first-level category that you encounter.
*
* For example:
*
* | Name | Parent | hierarchy |
* |-------------|----------------|------------------------ |
* | Top Category| null | [] |
* | Child | Top Category | [Top Category] |
* | Grand Child | Child | [Top Category, Child] |
*
*/
public class HierarchedCategory extends Category{

private List<ShortCategory> parentList;

public void setParentList(final List<ShortCategory> parentList) {
this.parentList = parentList;
}

public List<ShortCategory> getParentList() {
return parentList;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
HierarchedCategory that = (HierarchedCategory) o;
return Objects.equals(parentList, that.parentList);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), parentList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.dotmarketing.portlets.categories.model;

import java.io.Serializable;

/**
* Represents a {@link Category}, but only contains the most important data:
*
* - Category's name
* - Category's key
* - Category's inode
*/
public class ShortCategory implements Serializable {

private String categoryName;
private String inode;
private String key;

private ShortCategory(final Builder builder) {
this.categoryName = builder.categoryName;
this.inode = builder.inode;
this.key = builder.key;
}

public String getCategoryName() {
return categoryName;
}

public String getInode() {
return inode;
}

public String getKey() {
return key;
}

public static class Builder {
private String categoryName;
private String inode;
private String key;

public Builder setCategoryName(String categoryName) {
this.categoryName = categoryName;
return this;
}

public Builder setInode(String inode) {
this.inode = inode;
return this;
}

public Builder setKey(String key) {
this.key = key;
return this;
}

public ShortCategory build() {
return new ShortCategory(this);
}
}
}
Loading

0 comments on commit a33cb02

Please sign in to comment.