Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#28896 Including listParents as attribute on the response of the chil… #29116

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
dsilvam marked this conversation as resolved.
Show resolved Hide resolved
*/
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();
dsilvam marked this conversation as resolved.
Show resolved Hide resolved
}

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;
dsilvam marked this conversation as resolved.
Show resolved Hide resolved
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
Loading