From 476f28705615df1aa6235b94c2daad6f4b0291a6 Mon Sep 17 00:00:00 2001 From: freddyDOTCMS Date: Tue, 2 Jul 2024 09:27:32 -0600 Subject: [PATCH] #28896 Creating API Level class to search Categories on the entire tree --- .../categories/business/CategoryAPI.java | 13 ++ .../categories/business/CategoryAPIImpl.java | 37 ++++- .../categories/business/CategoryFactory.java | 20 ++- .../categories/business/CategoryAPITest.java | 127 +++++++++++++++++- 4 files changed, 192 insertions(+), 5 deletions(-) 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 1e286448a066..2989f3835799 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 @@ -484,4 +484,17 @@ Category findByVariable(final String variable, final User user, final boolean respectFrontendRoles) throws DotDataException, DotSecurityException; List getCategoriesFromContent(final Contentlet contentlet, final User user, boolean respectFrontendRoles ) throws DotDataException, DotSecurityException; + + /** + * Return a list of Categories regardless of their levels. + * + * @param searchCriteria Searching criteria + * @param user User to check Permission + * @param respectFrontendRoles true if you must respect Frontend Roles + * + * @return List of Category filtered + */ + PaginatedCategories findAll(final CategoryFactory.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 34d7ab311fde..729012cc08bb 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 @@ -22,6 +22,7 @@ import com.dotmarketing.util.InodeUtils; import com.dotmarketing.util.Logger; import com.dotmarketing.util.UtilMethods; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.liferay.portal.model.User; import java.util.ArrayList; @@ -48,8 +49,13 @@ public class CategoryAPIImpl implements CategoryAPI { private final PermissionAPI permissionAPI; public CategoryAPIImpl () { - categoryFactory = FactoryLocator.getCategoryFactory(); - permissionAPI = APILocator.getPermissionAPI(); + this(FactoryLocator.getCategoryFactory(), APILocator.getPermissionAPI()); + } + + @VisibleForTesting + public CategoryAPIImpl (final CategoryFactory categoryFactory, final PermissionAPI permissionAPI) { + this.categoryFactory = categoryFactory; + this.permissionAPI = permissionAPI; } /** @@ -943,4 +949,31 @@ private boolean hasCategoryFields(final ContentType contentType) { } + /** + * Default implementation. + * + * @param searchCriteria Searching criteria + * @param user User to check Permission + * @param respectFrontendRoles true if you must respect Frontend Roles + * + * @return + * @throws DotDataException + * @throws DotSecurityException + */ + @CloseDBIfOpened + @Override + public PaginatedCategories findAll(final CategoryFactory.CategorySearchCriteria searchCriteria, + final User user, boolean respectFrontendRoles) + throws DotDataException, DotSecurityException { + + if (searchCriteria.limit < 1) { + throw new IllegalArgumentException("Limit must be greater than 0"); + } + + final List categories = permissionAPI.filterCollection(categoryFactory.findAll(searchCriteria), + PermissionAPI.PERMISSION_READ, respectFrontendRoles, user); + + return getCategoriesSubList(searchCriteria.offset, searchCriteria.limit, categories, null); + } + } 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 01d1e34a71af..51345ef673bd 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 @@ -289,7 +289,7 @@ public abstract class CategoryFactory { * * @return List of Category filtered */ - public abstract Collection findAll(final CategorySearchCriteria searchCriteria) throws DotDataException; + public abstract List findAll(final CategorySearchCriteria searchCriteria) throws DotDataException; /** * Represents Search Criteria for {@link Category} searching, you cans set the follow: @@ -304,12 +304,15 @@ public static class CategorySearchCriteria { 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 { @@ -317,6 +320,8 @@ public static class Builder { 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; @@ -338,6 +343,17 @@ public Builder direction(OrderDirection 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 5a4d03115ca6..40a8563221aa 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 @@ -1,5 +1,6 @@ package com.dotmarketing.portlets.categories.business; +import static com.dotcms.util.CollectionsUtils.list; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -7,6 +8,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.dotcms.IntegrationTestBase; import com.dotcms.contenttype.business.ContentTypeAPIImpl; @@ -21,6 +24,7 @@ import com.dotcms.datagen.SiteDataGen; import com.dotcms.datagen.UserDataGen; import com.dotcms.util.IntegrationTestInitService; +import com.dotcms.util.pagination.OrderDirection; import com.dotmarketing.beans.Host; import com.dotmarketing.beans.Permission; import com.dotmarketing.business.APILocator; @@ -45,6 +49,8 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; + +import net.bytebuddy.utility.RandomString; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -91,7 +97,7 @@ public void findTopLevelCategories() throws DotSecurityException, DotDataExcepti int count = 10;//TODO: A -1 or 0 wont work in order to request all que records String filter = null; String sort = null; - + //Test the category API PaginatedCategories categories = categoryAPI.findTopLevelCategories(user, false, start, count, filter, sort); @@ -1537,4 +1543,123 @@ public void test_save_createTopLevelCategory_asLimitedUser_fail() categoryAPI.save(null, newCategory, limitedUser, false); } + + /** + * 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 PermissionAPI#filterCollection(List, int, boolean, User)} method to check permission + */ + @Test + public void getAllCategoriesFiltered() throws DotDataException, DotSecurityException { + final String inode = new RandomString().nextString(); + final String filter = new RandomString().nextString(); + final String orderBy = "category_key"; + + final CategoryFactory.CategorySearchCriteria searchingCriteria = + new CategoryFactory.CategorySearchCriteria.Builder() + .rootInode(inode) + .direction(OrderDirection.DESC) + .orderBy(orderBy) + .filter(filter) + .limit(10) + .build(); + + final User user = mock(); + + final Category category1 = mock(Category.class); + final Category category2 = mock(Category.class); + final Category category3 = mock(Category.class); + + final List categoriesAfterSearch = list(category1, category2, category3); + final List categoriesAfterPermission = list(category1, category2); + + final CategoryFactory categoryFactory = mock(); + when(categoryFactory.findAll(searchingCriteria)).thenReturn(categoriesAfterSearch); + + final PermissionAPI permissionAPI = mock(); + when(permissionAPI.filterCollection(categoriesAfterSearch, PermissionAPI.PERMISSION_READ, false, user)) + .thenReturn(categoriesAfterPermission); + + final CategoryAPI categoryAPI = new CategoryAPIImpl(categoryFactory, permissionAPI); + PaginatedCategories paginatedCategories = categoryAPI.findAll(searchingCriteria, user, false); + + assertEquals(categoriesAfterPermission.size(), (int) paginatedCategories.getTotalCount()); + assertTrue(categoriesAfterPermission.containsAll(paginatedCategories.getCategories())); + } + + /** + * Method to test: {@link CategoryAPIImpl#findAll(CategoryFactory.CategorySearchCriteria, User, boolean)} + * When: Create 9 Category, call the two times: + * first: limit =5, offset =0 + * second: limit =5, offset =5 + * + * Should: Return All the Categories with the 2 called + */ + @Test + public void getAllCategoriesFilteredWithPagination() throws DotDataException, DotSecurityException { + final String inode = new RandomString().nextString(); + final String filter = new RandomString().nextString(); + final String orderBy = "category_key"; + + final CategoryFactory.CategorySearchCriteria searchingCriteria_1 = + new CategoryFactory.CategorySearchCriteria.Builder() + .rootInode(inode) + .direction(OrderDirection.DESC) + .orderBy(orderBy) + .filter(filter) + .limit(5) + .offset(0) + .build(); + + final CategoryFactory.CategorySearchCriteria searchingCriteria_2 = + new CategoryFactory.CategorySearchCriteria.Builder() + .rootInode(inode) + .direction(OrderDirection.DESC) + .orderBy(orderBy) + .filter(filter) + .limit(5) + .offset(5) + .build(); + + final Category category1 = mock(Category.class); + final Category category2 = mock(Category.class); + final Category category3 = mock(Category.class); + final Category category4 = mock(Category.class); + final Category category5 = mock(Category.class); + final Category category6 = mock(Category.class); + final Category category7 = mock(Category.class); + final Category category8 = mock(Category.class); + final Category category9 = mock(Category.class); + + final User user = mock(); + + final List categories = list(category1, category2, category3, category4, category5, category6, + category7, category8, category9); + + final CategoryFactory categoryFactory = mock(); + when(categoryFactory.findAll(searchingCriteria_1)).thenReturn(categories); + when(categoryFactory.findAll(searchingCriteria_2)).thenReturn(categories); + + final PermissionAPI permissionAPI = mock(); + when(permissionAPI.filterCollection(categories, PermissionAPI.PERMISSION_READ, false, user)) + .thenReturn(categories); + + + + final CategoryAPI categoryAPI = new CategoryAPIImpl(categoryFactory, permissionAPI); + PaginatedCategories firstPage = categoryAPI.findAll(searchingCriteria_1, user, false); + + assertEquals(9, (int) firstPage.getTotalCount()); + assertEquals(5, firstPage.getCategories().size()); + assertTrue(list(category1, category2, category3, category4, category5).containsAll(firstPage.getCategories())); + + + PaginatedCategories secondPage = categoryAPI.findAll(searchingCriteria_2, user, false); + + assertEquals(9, (int) secondPage.getTotalCount()); + assertEquals(4, secondPage.getCategories().size()); + assertTrue(list(category6, category7, category8, category9).containsAll(secondPage.getCategories())); + } }