From 5f5c377532aee61b54334c3402ae60582bf48b00 Mon Sep 17 00:00:00 2001 From: MichalKinas Date: Mon, 3 Apr 2023 10:12:54 +0200 Subject: [PATCH] ACS-4966 Add option to include path for other endpoints, add unit tests covering path param --- .../rest/api/impl/CategoriesImpl.java | 20 +- .../rest/api/impl/CategoriesImplTest.java | 174 ++++++++++++++++++ 2 files changed, 193 insertions(+), 1 deletion(-) diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java index 5e25f27ed4..efa17be46e 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java @@ -134,6 +134,10 @@ public class CategoriesImpl implements Categories { category.setCount(0); } + if (parameters.getInclude().contains(INCLUDE_PATH_PARAM)) + { + category.setPath(nodeService.getPath(nodes.getNode(category.getId()).getNodeRef()).toDisplayPath(nodeService, permissionService)); + } }) .collect(Collectors.toList()); } @@ -183,6 +187,11 @@ public class CategoriesImpl implements Categories category.setCount(categoriesCount.getOrDefault(category.getId(), 0)); } + if (parameters.getInclude().contains(INCLUDE_PATH_PARAM)) + { + category.setPath(nodeService.getPath(categoryNodeRef).toDisplayPath(nodeService, permissionService)); + } + return category; } @@ -252,7 +261,16 @@ public class CategoriesImpl implements Categories linkNodeToCategories(contentNodeRef, categoryNodeRefs); - return categoryNodeRefs.stream().map(this::mapToCategory).collect(Collectors.toList()); + return categoryNodeRefs + .stream() + .map(this::mapToCategory) + .peek(category -> { + if (parameters.getInclude().contains(INCLUDE_PATH_PARAM)) + { + category.setPath(nodeService.getPath(nodes.getNode(category.getId()).getNodeRef()).toDisplayPath(nodeService, permissionService)); + } + }) + .collect(Collectors.toList()); } @Override diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java index 6d9dc98410..4d9a48f91c 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java @@ -28,6 +28,7 @@ package org.alfresco.rest.api.impl; import static org.alfresco.rest.api.Nodes.PATH_ROOT; import static org.alfresco.rest.api.impl.CategoriesImpl.INCLUDE_COUNT_PARAM; +import static org.alfresco.rest.api.impl.CategoriesImpl.INCLUDE_PATH_PARAM; import static org.alfresco.rest.api.impl.CategoriesImpl.INVALID_NODE_TYPE; import static org.alfresco.rest.api.impl.CategoriesImpl.NOT_A_VALID_CATEGORY; import static org.alfresco.rest.api.impl.CategoriesImpl.NOT_NULL_OR_EMPTY; @@ -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.NodeRef; 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.search.CategoryService; import org.alfresco.service.cmr.security.AccessStatus; @@ -252,6 +254,28 @@ public class CategoriesImplTest .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); + Path mockPath = new Path(); + given(nodesMock.getNode(any())).willReturn(createNode()); + given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation); + given(parametersMock.getInclude()).willReturn(List.of(INCLUDE_PATH_PARAM)); + given(nodeServiceMock.getPath(CATEGORY_NODE_REF)).willReturn(mockPath); + + // when + final Category actualCategory = objectUnderTest.getCategoryById(CATEGORY_ID, parametersMock); + + assertThat(actualCategory) + .isNotNull() + .extracting(Category::getPath) + .isNotNull() + .isEqualTo(""); + } + @Test public void testGetCategoryById_notACategory() { @@ -479,6 +503,37 @@ public class CategoriesImplTest .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); + final Path mockPath = new Path(); + 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(INCLUDE_PATH_PARAM)); + given(nodeServiceMock.getPath(any())).willReturn(mockPath); + final List categoryModels = new ArrayList<>(prepareCategories()); + + // when + final List 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(""); + } + @Test public void testCreateCategories_noPermissions() { @@ -628,6 +683,31 @@ public class CategoriesImplTest .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 childAssociationRefMocks = prepareChildAssocMocks(childrenCount, parentCategoryNodeRef); + final Path mockPath = new Path(); + given(nodeServiceMock.getChildAssocs(parentCategoryNodeRef)).willReturn(childAssociationRefMocks); + childAssociationRefMocks.forEach(this::prepareCategoryNodeMocks); + given(parametersMock.getInclude()).willReturn(List.of(INCLUDE_PATH_PARAM)); + given(nodeServiceMock.getPath(any())).willReturn(mockPath); + + // when + final List actualCategoryChildren = objectUnderTest.getCategoryChildren(PARENT_ID, parametersMock); + + assertThat(actualCategoryChildren) + .isNotNull() + .hasSize(3) + .extracting(Category::getPath) + .isNotNull() + .isEqualTo(List.of("", "", "")); + } + @Test public void testGetCategoryChildren_noChildren() { @@ -751,6 +831,32 @@ public class CategoriesImplTest .isEqualTo(1); } + @Test + public void testUpdateCategoryById_includePath() + { + final String categoryNewName = "categoryNewName"; + final Category fixedCategory = createCategoryOnlyWithName(categoryNewName); + 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); + final Path mockPath = new Path(); + 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(INCLUDE_PATH_PARAM)); + given(nodeServiceMock.getPath(CATEGORY_NODE_REF)).willReturn(mockPath); + + // when + final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, fixedCategory, parametersMock); + + assertThat(actualCategory) + .isNotNull() + .extracting(Category::getPath) + .isNotNull() + .isEqualTo(""); + } + @Test public void testUpdateCategoryById_noPermission() { @@ -918,6 +1024,7 @@ public class CategoriesImplTest then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef); then(nodeServiceMock).shouldHaveNoMoreInteractions(); final List expectedLinkedCategories = List.of(CATEGORY); + expectedLinkedCategories.get(0).setPath(null); assertThat(actualLinkedCategories) .isNotNull().usingRecursiveComparison() .isEqualTo(expectedLinkedCategories); @@ -984,6 +1091,37 @@ public class CategoriesImplTest .isEqualTo(expectedLinkedCategories); } + @Test + public void testLinkNodeToCategories_includePath() + { + final NodeRef categoryParentNodeRef = createNodeRefWithId(PARENT_ID); + final ChildAssociationRef parentAssociation = createAssociationOf(categoryParentNodeRef, CATEGORY_NODE_REF); + final Path mockPath = new Path(); + 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(INCLUDE_PATH_PARAM)); + given(nodeServiceMock.getPath(any())).willReturn(mockPath); + + // when + final List 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 expectedLinkedCategories = List.of(CATEGORY); + expectedLinkedCategories.get(0).setPath(""); + assertThat(actualLinkedCategories) + .isNotNull().usingRecursiveComparison() + .isEqualTo(expectedLinkedCategories); + } + @Test public void testLinkNodeToCategories_withPreviouslyLinkedCategories() { @@ -1168,11 +1306,47 @@ public class CategoriesImplTest then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef); then(nodeServiceMock).shouldHaveNoMoreInteractions(); final List 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); + final Path mockPath = new Path(); + 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(INCLUDE_PATH_PARAM)); + given(nodeServiceMock.getPath(any())).willReturn(mockPath); + + // when + final List 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 expectedCategories = List.of(CATEGORY); + expectedCategories.get(0).setPath(""); + assertThat(actualCategories) + .isNotNull().usingRecursiveComparison() + .isEqualTo(expectedCategories); + } + @Test public void testListCategoriesForNode_withInvalidNodeId() {