mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merge pull request #1855 from Alfresco/feature/ACS-4966_Add_path_to_categories_api
ACS-4966 Add path to Category API
This commit is contained in:
@@ -52,6 +52,11 @@ This must be unique within the parent category.
|
|||||||
*/
|
*/
|
||||||
private long count;
|
private long count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The path to this category.
|
||||||
|
*/
|
||||||
|
private String path;
|
||||||
|
|
||||||
public String getId()
|
public String getId()
|
||||||
{
|
{
|
||||||
return this.id;
|
return this.id;
|
||||||
@@ -102,6 +107,14 @@ This must be unique within the parent category.
|
|||||||
this.count = count;
|
this.count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o)
|
public boolean equals(Object o)
|
||||||
{
|
{
|
||||||
@@ -126,6 +139,7 @@ This must be unique within the parent category.
|
|||||||
", parentId='" + parentId + '\'' +
|
", parentId='" + parentId + '\'' +
|
||||||
", hasChildren=" + hasChildren +
|
", hasChildren=" + hasChildren +
|
||||||
", count=" + count +
|
", count=" + count +
|
||||||
|
", path=" + path +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.rest.categories;
|
||||||
|
|
||||||
|
import static org.alfresco.utility.data.RandomData.getRandomName;
|
||||||
|
import static org.alfresco.utility.report.log.Step.STEP;
|
||||||
|
import static org.springframework.http.HttpStatus.CREATED;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.alfresco.dataprep.CMISUtil;
|
||||||
|
import org.alfresco.rest.model.RestCategoryLinkBodyModel;
|
||||||
|
import org.alfresco.rest.model.RestCategoryModel;
|
||||||
|
import org.alfresco.rest.model.RestCategoryModelsCollection;
|
||||||
|
import org.alfresco.utility.Utility;
|
||||||
|
import org.alfresco.utility.model.FileModel;
|
||||||
|
import org.alfresco.utility.model.FolderModel;
|
||||||
|
import org.alfresco.utility.model.SiteModel;
|
||||||
|
import org.alfresco.utility.model.TestGroup;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
public class CategoriesPathTests extends CategoriesRestTest
|
||||||
|
{
|
||||||
|
private FileModel file;
|
||||||
|
private RestCategoryModel category;
|
||||||
|
|
||||||
|
@BeforeClass(alwaysRun = true)
|
||||||
|
@Override
|
||||||
|
public void dataPreparation() throws Exception
|
||||||
|
{
|
||||||
|
STEP("Create user and site");
|
||||||
|
user = dataUser.createRandomTestUser();
|
||||||
|
SiteModel site = dataSite.usingUser(user).createPublicRandomSite();
|
||||||
|
|
||||||
|
STEP("Create a folder, file in it and a category");
|
||||||
|
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
|
||||||
|
file = dataContent.usingUser(user).usingResource(folder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
|
||||||
|
category = prepareCategoryUnderRoot();
|
||||||
|
|
||||||
|
STEP("Wait for indexing to complete");
|
||||||
|
Utility.sleep(1000, 60000, () -> restClient.authenticateUser(user)
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingCategory(category)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.getCategory()
|
||||||
|
.assertThat()
|
||||||
|
.field(FIELD_PATH)
|
||||||
|
.isNotNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify path for a category got by ID.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API })
|
||||||
|
public void testGetCategoryById_includePath()
|
||||||
|
{
|
||||||
|
STEP("Get category and verify if path is a general path for categories");
|
||||||
|
final RestCategoryModel actualCategory = restClient.authenticateUser(user)
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingCategory(category)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.getCategory();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(OK);
|
||||||
|
actualCategory.assertThat().field(FIELD_ID).is(category.getId());
|
||||||
|
actualCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify path for category.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API })
|
||||||
|
public void testGetCategories_includePath()
|
||||||
|
{
|
||||||
|
STEP("Get few categories and verify its paths");
|
||||||
|
final RestCategoryModel parentCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
|
||||||
|
final RestCategoryModelsCollection actualCategories = restClient.authenticateUser(user)
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingCategory(parentCategory)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.getCategoryChildren();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(OK);
|
||||||
|
assertTrue(actualCategories.getEntries().stream()
|
||||||
|
.map(RestCategoryModel::onModel)
|
||||||
|
.allMatch(cat -> cat.getPath().equals("/categories/General")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify path for child category.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API })
|
||||||
|
public void testGetChildCategory_includePath()
|
||||||
|
{
|
||||||
|
STEP("Create parent and child categories");
|
||||||
|
final RestCategoryModel parentCategory = prepareCategoryUnderRoot();
|
||||||
|
final RestCategoryModel childCategory = prepareCategoryUnder(parentCategory);
|
||||||
|
|
||||||
|
STEP("Verify path for created child categories");
|
||||||
|
final RestCategoryModelsCollection actualCategories = restClient.authenticateUser(user)
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingCategory(parentCategory)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.getCategoryChildren();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(OK);
|
||||||
|
actualCategories.getEntries().stream()
|
||||||
|
.map(RestCategoryModel::onModel)
|
||||||
|
.forEach(cat -> cat.assertThat().field(FIELD_PATH).is("/categories/General/" + parentCategory.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create category and verify that it has a path.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API })
|
||||||
|
public void testCreateCategory_includingPath()
|
||||||
|
{
|
||||||
|
STEP("Create a category under root and verify if path is a general path for categories");
|
||||||
|
final String categoryName = getRandomName("Category");
|
||||||
|
final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
|
||||||
|
final RestCategoryModel aCategory = createCategoryModelWithName(categoryName);
|
||||||
|
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||||
|
.withCoreAPI()
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.usingCategory(rootCategory)
|
||||||
|
.createSingleCategory(aCategory);
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(CREATED);
|
||||||
|
createdCategory.assertThat().field(FIELD_NAME).is(categoryName);
|
||||||
|
createdCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update category and verify that it has a path.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API })
|
||||||
|
public void testUpdateCategory_includePath()
|
||||||
|
{
|
||||||
|
STEP("Update linked category and verify if path is a general path for categories");
|
||||||
|
final String categoryNewName = getRandomName("NewCategoryName");
|
||||||
|
final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(categoryNewName);
|
||||||
|
final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingCategory(category)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.updateCategory(fixedCategoryModel);
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(OK);
|
||||||
|
updatedCategory.assertThat().field(FIELD_ID).is(category.getId());
|
||||||
|
updatedCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link node to categories and verify that they have path.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API })
|
||||||
|
public void testLinkNodeToCategories_includePath()
|
||||||
|
{
|
||||||
|
STEP("Link node to categories and verify if path is a general path");
|
||||||
|
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
|
||||||
|
final RestCategoryModel linkedCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingNode(file)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.linkToCategory(categoryLinkModel);
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(CREATED);
|
||||||
|
linkedCategory.assertThat().field(FIELD_ID).is(category.getId());
|
||||||
|
linkedCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List categories for given node and verify that they have a path.
|
||||||
|
*/
|
||||||
|
@Test(groups = { TestGroup.REST_API })
|
||||||
|
public void testListCategoriesForNode_includePath()
|
||||||
|
{
|
||||||
|
STEP("Link file to category");
|
||||||
|
final RestCategoryLinkBodyModel categoryLink = createCategoryLinkModelWithId(category.getId());
|
||||||
|
final RestCategoryModel linkedCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingNode(file)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.linkToCategory(categoryLink);
|
||||||
|
|
||||||
|
STEP("Get linked category and verify if path is a general path");
|
||||||
|
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(dataUser.getAdminUser())
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingNode(file)
|
||||||
|
.include(INCLUDE_PATH_PARAM)
|
||||||
|
.getLinkedCategories();
|
||||||
|
|
||||||
|
restClient.assertStatusCodeIs(OK);
|
||||||
|
linkedCategories.assertThat().entriesListCountIs(1);
|
||||||
|
linkedCategories.getEntries().get(0).onModel().assertThat().field(FIELD_ID).is(category.getId());
|
||||||
|
linkedCategories.getEntries().get(0).onModel().assertThat().field(FIELD_PATH).is("/categories/General");
|
||||||
|
}
|
||||||
|
}
|
@@ -46,6 +46,7 @@ import org.testng.annotations.BeforeClass;
|
|||||||
abstract class CategoriesRestTest extends RestTest
|
abstract class CategoriesRestTest extends RestTest
|
||||||
{
|
{
|
||||||
protected static final String INCLUDE_COUNT_PARAM = "count";
|
protected static final String INCLUDE_COUNT_PARAM = "count";
|
||||||
|
protected static final String INCLUDE_PATH_PARAM = "path";
|
||||||
protected static final String ROOT_CATEGORY_ID = "-root-";
|
protected static final String ROOT_CATEGORY_ID = "-root-";
|
||||||
protected static final String CATEGORY_NAME_PREFIX = "CategoryName";
|
protected static final String CATEGORY_NAME_PREFIX = "CategoryName";
|
||||||
protected static final String FIELD_NAME = "name";
|
protected static final String FIELD_NAME = "name";
|
||||||
@@ -53,6 +54,7 @@ abstract class CategoriesRestTest extends RestTest
|
|||||||
protected static final String FIELD_PARENT_ID = "parentId";
|
protected static final String FIELD_PARENT_ID = "parentId";
|
||||||
protected static final String FIELD_HAS_CHILDREN = "hasChildren";
|
protected static final String FIELD_HAS_CHILDREN = "hasChildren";
|
||||||
protected static final String FIELD_COUNT = "count";
|
protected static final String FIELD_COUNT = "count";
|
||||||
|
protected static final String FIELD_PATH = "path";
|
||||||
|
|
||||||
protected UserModel user;
|
protected UserModel user;
|
||||||
|
|
||||||
|
@@ -111,6 +111,11 @@ public class CategoriesImpl implements Categories
|
|||||||
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
|
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||||
|
{
|
||||||
|
category.setPath(getCategoryPath(category));
|
||||||
|
}
|
||||||
|
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +133,10 @@ public class CategoriesImpl implements Categories
|
|||||||
{
|
{
|
||||||
category.setCount(0);
|
category.setCount(0);
|
||||||
}
|
}
|
||||||
|
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||||
|
{
|
||||||
|
category.setPath(getCategoryPath(category));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@@ -136,10 +145,17 @@ public class CategoriesImpl implements Categories
|
|||||||
public List<Category> getCategoryChildren(final StoreRef storeRef, final String parentCategoryId, final Parameters parameters)
|
public List<Category> getCategoryChildren(final StoreRef storeRef, final String parentCategoryId, final Parameters parameters)
|
||||||
{
|
{
|
||||||
final NodeRef parentNodeRef = getCategoryNodeRef(storeRef, parentCategoryId);
|
final NodeRef parentNodeRef = getCategoryNodeRef(storeRef, parentCategoryId);
|
||||||
final List<Category> categories = nodeService.getChildAssocs(parentNodeRef).stream()
|
final List<Category> categories = nodeService.getChildAssocs(parentNodeRef)
|
||||||
|
.stream()
|
||||||
.filter(ca -> ContentModel.ASSOC_SUBCATEGORIES.equals(ca.getTypeQName()))
|
.filter(ca -> ContentModel.ASSOC_SUBCATEGORIES.equals(ca.getTypeQName()))
|
||||||
.map(ChildAssociationRef::getChildRef)
|
.map(ChildAssociationRef::getChildRef)
|
||||||
.map(this::mapToCategory)
|
.map(this::mapToCategory)
|
||||||
|
.peek(category -> {
|
||||||
|
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||||
|
{
|
||||||
|
category.setPath(getCategoryPath(category));
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
if (parameters.getInclude().contains(INCLUDE_COUNT_PARAM))
|
if (parameters.getInclude().contains(INCLUDE_COUNT_PARAM))
|
||||||
@@ -170,6 +186,11 @@ public class CategoriesImpl implements Categories
|
|||||||
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
|
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||||
|
{
|
||||||
|
category.setPath(getCategoryPath(category));
|
||||||
|
}
|
||||||
|
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +221,16 @@ public class CategoriesImpl implements Categories
|
|||||||
}
|
}
|
||||||
final Collection<NodeRef> actualCategories = DefaultTypeConverter.INSTANCE.getCollection(NodeRef.class, currentCategories);
|
final Collection<NodeRef> actualCategories = DefaultTypeConverter.INSTANCE.getCollection(NodeRef.class, currentCategories);
|
||||||
|
|
||||||
return actualCategories.stream().map(this::mapToCategory).collect(Collectors.toList());
|
return actualCategories
|
||||||
|
.stream()
|
||||||
|
.map(this::mapToCategory)
|
||||||
|
.peek(category -> {
|
||||||
|
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||||
|
{
|
||||||
|
category.setPath(getCategoryPath(category));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,7 +260,16 @@ public class CategoriesImpl implements Categories
|
|||||||
|
|
||||||
linkNodeToCategories(contentNodeRef, categoryNodeRefs);
|
linkNodeToCategories(contentNodeRef, categoryNodeRefs);
|
||||||
|
|
||||||
return categoryNodeRefs.stream().map(this::mapToCategory).collect(Collectors.toList());
|
return categoryNodeRefs
|
||||||
|
.stream()
|
||||||
|
.map(this::mapToCategory)
|
||||||
|
.peek(category -> {
|
||||||
|
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||||
|
{
|
||||||
|
category.setPath(getCategoryPath(category));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -475,4 +514,16 @@ public class CategoriesImpl implements Categories
|
|||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.toMap(pair -> pair.getFirst().toString().replace(idPrefix, StringUtils.EMPTY), Pair::getSecond));
|
.collect(Collectors.toMap(pair -> pair.getFirst().toString().replace(idPrefix, StringUtils.EMPTY), Pair::getSecond));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get path for a given category in human-readable form.
|
||||||
|
*
|
||||||
|
* @param category Category to provide path for.
|
||||||
|
* @return Path for a category in human-readable form.
|
||||||
|
*/
|
||||||
|
private String getCategoryPath(final Category category)
|
||||||
|
{
|
||||||
|
final NodeRef categoryNodeRef = nodes.getNode(category.getId()).getNodeRef();
|
||||||
|
return nodeService.getPath(categoryNodeRef).toDisplayPath(nodeService, permissionService);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,6 +35,7 @@ public class Category
|
|||||||
private String parentId;
|
private String parentId;
|
||||||
private boolean hasChildren;
|
private boolean hasChildren;
|
||||||
private Integer count;
|
private Integer count;
|
||||||
|
private String path;
|
||||||
|
|
||||||
public String getId()
|
public String getId()
|
||||||
{
|
{
|
||||||
@@ -91,6 +92,14 @@ public class Category
|
|||||||
this.count = count;
|
this.count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o)
|
public boolean equals(Object o)
|
||||||
{
|
{
|
||||||
@@ -100,19 +109,20 @@ public class Category
|
|||||||
return false;
|
return false;
|
||||||
Category category = (Category) o;
|
Category category = (Category) o;
|
||||||
return hasChildren == category.hasChildren && Objects.equals(id, category.id) && Objects.equals(name, category.name) && Objects.equals(parentId, category.parentId)
|
return hasChildren == category.hasChildren && Objects.equals(id, category.id) && Objects.equals(name, category.name) && Objects.equals(parentId, category.parentId)
|
||||||
&& Objects.equals(count, category.count);
|
&& Objects.equals(count, category.count) && Objects.equals(path, category.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
{
|
{
|
||||||
return Objects.hash(id, name, parentId, hasChildren, count);
|
return Objects.hash(id, name, parentId, hasChildren, count, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return "Category{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", parentId='" + parentId + '\'' + ", hasChildren=" + hasChildren + ", count=" + count + '}';
|
return "Category{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", parentId='" + parentId + '\'' + ", hasChildren=" + hasChildren
|
||||||
|
+ ", count=" + count + ", path=" + path + '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Builder builder()
|
public static Builder builder()
|
||||||
@@ -127,6 +137,7 @@ public class Category
|
|||||||
private String parentId;
|
private String parentId;
|
||||||
private boolean hasChildren;
|
private boolean hasChildren;
|
||||||
private Integer count;
|
private Integer count;
|
||||||
|
private String path;
|
||||||
|
|
||||||
public Builder id(String id)
|
public Builder id(String id)
|
||||||
{
|
{
|
||||||
@@ -158,6 +169,12 @@ public class Category
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder path(String path)
|
||||||
|
{
|
||||||
|
this.path = path;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Category create()
|
public Category create()
|
||||||
{
|
{
|
||||||
final Category category = new Category();
|
final Category category = new Category();
|
||||||
@@ -166,6 +183,7 @@ public class Category
|
|||||||
category.setParentId(parentId);
|
category.setParentId(parentId);
|
||||||
category.setHasChildren(hasChildren);
|
category.setHasChildren(hasChildren);
|
||||||
category.setCount(count);
|
category.setCount(count);
|
||||||
|
category.setPath(path);
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -60,6 +60,7 @@ import java.util.stream.IntStream;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.transfer.PathHelper;
|
||||||
import org.alfresco.rest.api.Nodes;
|
import org.alfresco.rest.api.Nodes;
|
||||||
import org.alfresco.rest.api.model.Category;
|
import org.alfresco.rest.api.model.Category;
|
||||||
import org.alfresco.rest.api.model.Node;
|
import org.alfresco.rest.api.model.Node;
|
||||||
@@ -71,6 +72,7 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
|
|||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.repository.Path;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.search.CategoryService;
|
import org.alfresco.service.cmr.search.CategoryService;
|
||||||
import org.alfresco.service.cmr.security.AccessStatus;
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
@@ -100,6 +102,9 @@ public class CategoriesImplTest
|
|||||||
private static final Category CATEGORY = createDefaultCategory();
|
private static final Category CATEGORY = createDefaultCategory();
|
||||||
private static final String CONTENT_NODE_ID = "content-node-id";
|
private static final String CONTENT_NODE_ID = "content-node-id";
|
||||||
private static final NodeRef CONTENT_NODE_REF = createNodeRefWithId(CONTENT_NODE_ID);
|
private static final NodeRef CONTENT_NODE_REF = createNodeRefWithId(CONTENT_NODE_ID);
|
||||||
|
private static final String MOCK_ROOT_LEVEL = "/{mockRootLevel}";
|
||||||
|
private static final String MOCK_CHILD_LEVEL = "/{mockChild}";
|
||||||
|
private static final String MOCK_CATEGORY_PATH = "//" + MOCK_ROOT_LEVEL + "//" + MOCK_CHILD_LEVEL;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private Nodes nodesMock;
|
private Nodes nodesMock;
|
||||||
@@ -252,6 +257,27 @@ public class CategoriesImplTest
|
|||||||
.isEqualTo(1);
|
.isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCategoryById_includePath()
|
||||||
|
{
|
||||||
|
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
|
||||||
|
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||||
|
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
|
||||||
|
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||||
|
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||||
|
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final Category actualCategory = objectUnderTest.getCategoryById(CATEGORY_ID, parametersMock);
|
||||||
|
|
||||||
|
assertThat(actualCategory)
|
||||||
|
.isNotNull()
|
||||||
|
.extracting(Category::getPath)
|
||||||
|
.isNotNull()
|
||||||
|
.isEqualTo(MOCK_CATEGORY_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetCategoryById_notACategory()
|
public void testGetCategoryById_notACategory()
|
||||||
{
|
{
|
||||||
@@ -479,6 +505,36 @@ public class CategoriesImplTest
|
|||||||
.isEqualTo(0);
|
.isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateCategory_includePath()
|
||||||
|
{
|
||||||
|
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
|
||||||
|
final NodeRef categoryNodeRef = createNodeRefWithId(CATEGORY_ID);
|
||||||
|
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||||
|
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
|
||||||
|
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
|
||||||
|
given(categoryServiceMock.createCategory(parentCategoryNodeRef, CATEGORY_NAME)).willReturn(categoryNodeRef);
|
||||||
|
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||||
|
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||||
|
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||||
|
final List<Category> categoryModels = new ArrayList<>(prepareCategories());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final List<Category> actualCreatedCategories = objectUnderTest.createSubcategories(PARENT_ID, categoryModels, parametersMock);
|
||||||
|
|
||||||
|
then(categoryServiceMock).should().createCategory(any(), any());
|
||||||
|
then(categoryServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
|
||||||
|
assertThat(actualCreatedCategories)
|
||||||
|
.isNotNull()
|
||||||
|
.hasSize(1)
|
||||||
|
.element(0)
|
||||||
|
.extracting(Category::getPath)
|
||||||
|
.isNotNull()
|
||||||
|
.isEqualTo(MOCK_CATEGORY_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateCategories_noPermissions()
|
public void testCreateCategories_noPermissions()
|
||||||
{
|
{
|
||||||
@@ -628,6 +684,30 @@ public class CategoriesImplTest
|
|||||||
.isEqualTo(List.of(0, 2, 0));
|
.isEqualTo(List.of(0, 2, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCategoryChildren_includePath()
|
||||||
|
{
|
||||||
|
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||||
|
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
|
||||||
|
given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
|
||||||
|
final int childrenCount = 3;
|
||||||
|
final List<ChildAssociationRef> childAssociationRefMocks = prepareChildAssocMocks(childrenCount, parentCategoryNodeRef);
|
||||||
|
given(nodeServiceMock.getChildAssocs(parentCategoryNodeRef)).willReturn(childAssociationRefMocks);
|
||||||
|
childAssociationRefMocks.forEach(this::prepareCategoryNodeMocks);
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||||
|
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final List<Category> actualCategoryChildren = objectUnderTest.getCategoryChildren(PARENT_ID, parametersMock);
|
||||||
|
|
||||||
|
assertThat(actualCategoryChildren)
|
||||||
|
.isNotNull()
|
||||||
|
.hasSize(3)
|
||||||
|
.extracting(Category::getPath)
|
||||||
|
.isNotNull()
|
||||||
|
.isEqualTo(List.of(MOCK_CATEGORY_PATH, MOCK_CATEGORY_PATH, MOCK_CATEGORY_PATH));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetCategoryChildren_noChildren()
|
public void testGetCategoryChildren_noChildren()
|
||||||
{
|
{
|
||||||
@@ -751,6 +831,32 @@ public class CategoriesImplTest
|
|||||||
.isEqualTo(1);
|
.isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateCategoryById_includePath()
|
||||||
|
{
|
||||||
|
final String categoryNewName = "categoryNewName";
|
||||||
|
final Category fixedCategory = createCategoryOnlyWithName(categoryNewName);
|
||||||
|
// simulate path provided by client to check if it will be ignored
|
||||||
|
fixedCategory.setPath("/test/TestCat");
|
||||||
|
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
|
||||||
|
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||||
|
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
|
||||||
|
given(nodesMock.getNode(any())).willReturn(createNode(categoryNewName));
|
||||||
|
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||||
|
given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||||
|
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, fixedCategory, parametersMock);
|
||||||
|
|
||||||
|
assertThat(actualCategory)
|
||||||
|
.isNotNull()
|
||||||
|
.extracting(Category::getPath)
|
||||||
|
.isNotNull()
|
||||||
|
.isEqualTo(MOCK_CATEGORY_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateCategoryById_noPermission()
|
public void testUpdateCategoryById_noPermission()
|
||||||
{
|
{
|
||||||
@@ -918,6 +1024,7 @@ public class CategoriesImplTest
|
|||||||
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||||
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||||
final List<Category> expectedLinkedCategories = List.of(CATEGORY);
|
final List<Category> expectedLinkedCategories = List.of(CATEGORY);
|
||||||
|
expectedLinkedCategories.get(0).setPath(null);
|
||||||
assertThat(actualLinkedCategories)
|
assertThat(actualLinkedCategories)
|
||||||
.isNotNull().usingRecursiveComparison()
|
.isNotNull().usingRecursiveComparison()
|
||||||
.isEqualTo(expectedLinkedCategories);
|
.isEqualTo(expectedLinkedCategories);
|
||||||
@@ -984,6 +1091,36 @@ public class CategoriesImplTest
|
|||||||
.isEqualTo(expectedLinkedCategories);
|
.isEqualTo(expectedLinkedCategories);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLinkNodeToCategories_includePath()
|
||||||
|
{
|
||||||
|
final NodeRef categoryParentNodeRef = createNodeRefWithId(PARENT_ID);
|
||||||
|
final ChildAssociationRef parentAssociation = createAssociationOf(categoryParentNodeRef, CATEGORY_NODE_REF);
|
||||||
|
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||||
|
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||||
|
given(nodeServiceMock.hasAspect(any(), any())).willReturn(true);
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||||
|
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final List<Category> actualLinkedCategories = objectUnderTest.linkNodeToCategories(CONTENT_NODE_ID, List.of(CATEGORY), parametersMock);
|
||||||
|
|
||||||
|
then(nodesMock).should(times(2)).getNode(CATEGORY_ID);
|
||||||
|
then(nodeServiceMock).should().getChildAssocs(CATEGORY_NODE_REF, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
|
||||||
|
then(nodeServiceMock).should().getPrimaryParent(CATEGORY_NODE_REF);
|
||||||
|
then(nodeServiceMock).should().getParentAssocs(CATEGORY_NODE_REF);
|
||||||
|
then(nodeServiceMock).should().hasAspect(CONTENT_NODE_REF, ContentModel.ASPECT_GEN_CLASSIFIABLE);
|
||||||
|
then(nodeServiceMock).should().getProperty(CONTENT_NODE_REF, ContentModel.PROP_CATEGORIES);
|
||||||
|
final Serializable expectedCategories = (Serializable) List.of(CATEGORY_NODE_REF);
|
||||||
|
then(nodeServiceMock).should().setProperty(CONTENT_NODE_REF, ContentModel.PROP_CATEGORIES, expectedCategories);
|
||||||
|
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||||
|
final List<Category> expectedLinkedCategories = List.of(CATEGORY);
|
||||||
|
expectedLinkedCategories.get(0).setPath(MOCK_CATEGORY_PATH);
|
||||||
|
assertThat(actualLinkedCategories)
|
||||||
|
.isNotNull().usingRecursiveComparison()
|
||||||
|
.isEqualTo(expectedLinkedCategories);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLinkNodeToCategories_withPreviouslyLinkedCategories()
|
public void testLinkNodeToCategories_withPreviouslyLinkedCategories()
|
||||||
{
|
{
|
||||||
@@ -1168,6 +1305,41 @@ public class CategoriesImplTest
|
|||||||
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||||
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||||
final List<Category> expectedCategories = List.of(CATEGORY);
|
final List<Category> expectedCategories = List.of(CATEGORY);
|
||||||
|
expectedCategories.get(0).setPath(null);
|
||||||
|
assertThat(actualCategories)
|
||||||
|
.isNotNull().usingRecursiveComparison()
|
||||||
|
.isEqualTo(expectedCategories);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListCategoriesForNode_includePath()
|
||||||
|
{
|
||||||
|
final NodeRef categoryParentNodeRef = createNodeRefWithId(PARENT_ID);
|
||||||
|
final ChildAssociationRef parentAssociation = createAssociationOf(categoryParentNodeRef, CATEGORY_NODE_REF);
|
||||||
|
given(nodeServiceMock.getProperty(any(), eq(ContentModel.PROP_CATEGORIES))).willReturn((Serializable) List.of(CATEGORY_NODE_REF));
|
||||||
|
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||||
|
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||||
|
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||||
|
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final List<Category> actualCategories = objectUnderTest.listCategoriesForNode(CONTENT_NODE_ID, parametersMock);
|
||||||
|
|
||||||
|
then(nodesMock).should().validateOrLookupNode(CONTENT_NODE_ID);
|
||||||
|
then(permissionServiceMock).should().hasReadPermission(CONTENT_NODE_REF);
|
||||||
|
then(permissionServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
then(typeConstraint).should().matches(CONTENT_NODE_REF);
|
||||||
|
then(typeConstraint).shouldHaveNoMoreInteractions();
|
||||||
|
then(nodesMock).should(times(2)).getNode(CATEGORY_ID);
|
||||||
|
then(nodesMock).shouldHaveNoMoreInteractions();
|
||||||
|
then(nodeServiceMock).should().getProperty(CONTENT_NODE_REF, ContentModel.PROP_CATEGORIES);
|
||||||
|
then(nodeServiceMock).should().getChildAssocs(CATEGORY_NODE_REF, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
|
||||||
|
then(nodeServiceMock).should().getPrimaryParent(CATEGORY_NODE_REF);
|
||||||
|
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||||
|
then(nodeServiceMock).should().getPath(any());
|
||||||
|
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
final List<Category> expectedCategories = List.of(CATEGORY);
|
||||||
|
expectedCategories.get(0).setPath(MOCK_CATEGORY_PATH);
|
||||||
assertThat(actualCategories)
|
assertThat(actualCategories)
|
||||||
.isNotNull().usingRecursiveComparison()
|
.isNotNull().usingRecursiveComparison()
|
||||||
.isEqualTo(expectedCategories);
|
.isEqualTo(expectedCategories);
|
||||||
@@ -1329,4 +1501,13 @@ public class CategoriesImplTest
|
|||||||
{
|
{
|
||||||
return new ChildAssociationRef(ContentModel.ASSOC_SUBCATEGORIES, parentNode, childNodeName, childNode);
|
return new ChildAssociationRef(ContentModel.ASSOC_SUBCATEGORIES, parentNode, childNodeName, childNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Path mockCategoryPath()
|
||||||
|
{
|
||||||
|
final Path mockPath = new Path();
|
||||||
|
mockPath.append(PathHelper.stringToPath(MOCK_ROOT_LEVEL));
|
||||||
|
mockPath.append(PathHelper.stringToPath(MOCK_CHILD_LEVEL));
|
||||||
|
mockPath.append(PathHelper.stringToPath("/"));
|
||||||
|
return mockPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user