mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
ACS-4030: Delete category endpoint (#1618)
* ACS-4030: Delete category endpoint implementation and tests
This commit is contained in:
committed by
GitHub
parent
28114338c8
commit
88b6a8e5b3
@@ -92,4 +92,16 @@ public class Categories extends ModelRequest<Categories>
|
|||||||
return restWrapper.processModels(RestCategoryModelsCollection.class, request);
|
return restWrapper.processModels(RestCategoryModelsCollection.class, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete category.
|
||||||
|
*
|
||||||
|
* - DELETE /categories/{categoryId}
|
||||||
|
*/
|
||||||
|
public void deleteCategory()
|
||||||
|
{
|
||||||
|
RestRequest request = RestRequest.
|
||||||
|
simpleRequest(HttpMethod.DELETE, "/categories/{categoryId}", category.getId());
|
||||||
|
restWrapper.processEmptyModel(request);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2022 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 org.alfresco.rest.RestTest;
|
||||||
|
import org.alfresco.rest.model.RestCategoryModel;
|
||||||
|
import org.alfresco.utility.data.RandomData;
|
||||||
|
import org.alfresco.utility.model.FolderModel;
|
||||||
|
import org.alfresco.utility.model.SiteModel;
|
||||||
|
import org.alfresco.utility.model.TestGroup;
|
||||||
|
import org.alfresco.utility.model.UserModel;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.alfresco.utility.report.log.Step.STEP;
|
||||||
|
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||||
|
import static org.springframework.http.HttpStatus.CREATED;
|
||||||
|
import static org.springframework.http.HttpStatus.FORBIDDEN;
|
||||||
|
import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||||
|
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||||
|
|
||||||
|
public class DeleteCategoriesTests extends RestTest {
|
||||||
|
|
||||||
|
private UserModel user;
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeClass(alwaysRun = true)
|
||||||
|
public void dataPreparation() throws Exception
|
||||||
|
{
|
||||||
|
STEP("Create a user");
|
||||||
|
user = dataUser.createRandomTestUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check we can delete a category.
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API})
|
||||||
|
public void testDeleteCategory()
|
||||||
|
{
|
||||||
|
STEP("Create a category and send a request to delete it.");
|
||||||
|
RestCategoryModel aCategory = createCategory();
|
||||||
|
restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingCategory(aCategory).deleteCategory();
|
||||||
|
restClient.assertStatusCodeIs(NO_CONTENT);
|
||||||
|
|
||||||
|
STEP("Ensure that the category has been deleted by sending a GET request and receiving 404.");
|
||||||
|
restClient.authenticateUser(user).withCoreAPI().usingCategory(aCategory).getCategory();
|
||||||
|
restClient.assertStatusCodeIs(NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check we get an error when trying to delete a category as a non-admin user.
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API})
|
||||||
|
public void testDeleteCategoryAsRegularUser_andFail()
|
||||||
|
{
|
||||||
|
RestCategoryModel aCategory = createCategory();
|
||||||
|
restClient.authenticateUser(user).withCoreAPI().usingCategory(aCategory).deleteCategory();
|
||||||
|
restClient.assertStatusCodeIs(FORBIDDEN).assertLastError().containsSummary("Current user does not have permission to delete a category");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check we receive 404 error when trying to delete a category with a non-existent node id.
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API})
|
||||||
|
public void testDeleteNonExistentCategory()
|
||||||
|
{
|
||||||
|
STEP("Get category with non-existent id");
|
||||||
|
final RestCategoryModel rootCategory = new RestCategoryModel();
|
||||||
|
final String id = "non-existing-dummy-id";
|
||||||
|
rootCategory.setId(id);
|
||||||
|
|
||||||
|
STEP("Attempt to delete category with non-existent id and receive 404");
|
||||||
|
restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingCategory(rootCategory).deleteCategory();
|
||||||
|
restClient.assertStatusCodeIs(NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to delete a category when providing a node id that doesn't belong to a category
|
||||||
|
*/
|
||||||
|
@Test(groups = {TestGroup.REST_API})
|
||||||
|
public void testDeleteCategory_givenNonCategoryNodeId()
|
||||||
|
{
|
||||||
|
STEP("Create a site and a folder inside it");
|
||||||
|
final SiteModel site = dataSite.usingUser(user).createPublicRandomSite();
|
||||||
|
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
|
||||||
|
String id = folder.getNodeRef();
|
||||||
|
|
||||||
|
STEP("Create a category, set its id to the folder id and attempt to delete it");
|
||||||
|
final RestCategoryModel aCategory = new RestCategoryModel();
|
||||||
|
aCategory.setId(id);
|
||||||
|
restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingCategory(aCategory).deleteCategory();
|
||||||
|
restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Node id does not refer to a valid category");
|
||||||
|
}
|
||||||
|
|
||||||
|
public RestCategoryModel createCategory()
|
||||||
|
{
|
||||||
|
final RestCategoryModel rootCategory = new RestCategoryModel();
|
||||||
|
rootCategory.setId("-root-");
|
||||||
|
final RestCategoryModel aCategory = new RestCategoryModel();
|
||||||
|
aCategory.setName(RandomData.getRandomName("Category"));
|
||||||
|
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||||
|
.withCoreAPI()
|
||||||
|
.usingCategory(rootCategory)
|
||||||
|
.createSingleCategory(aCategory);
|
||||||
|
restClient.assertStatusCodeIs(CREATED);
|
||||||
|
|
||||||
|
return createdCategory;
|
||||||
|
}
|
||||||
|
}
|
@@ -32,7 +32,6 @@ import org.alfresco.rest.api.model.Category;
|
|||||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||||
import org.alfresco.service.Experimental;
|
import org.alfresco.service.Experimental;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
|
|
||||||
@Experimental
|
@Experimental
|
||||||
public interface Categories
|
public interface Categories
|
||||||
@@ -42,4 +41,7 @@ public interface Categories
|
|||||||
List<Category> createSubcategories(String parentCategoryId, List<Category> categories, Parameters parameters);
|
List<Category> createSubcategories(String parentCategoryId, List<Category> categories, Parameters parameters);
|
||||||
|
|
||||||
CollectionWithPagingInfo<Category> getCategoryChildren(String parentCategoryId, Parameters params);
|
CollectionWithPagingInfo<Category> getCategoryChildren(String parentCategoryId, Parameters params);
|
||||||
|
|
||||||
|
void deleteCategoryById(String id, Parameters params);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,8 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
|
|||||||
* @author mpichura
|
* @author mpichura
|
||||||
*/
|
*/
|
||||||
@EntityResource(name = "categories", title = "Categories")
|
@EntityResource(name = "categories", title = "Categories")
|
||||||
public class CategoriesEntityResource implements EntityResourceAction.ReadById<Category>
|
public class CategoriesEntityResource implements EntityResourceAction.ReadById<Category>,
|
||||||
|
EntityResourceAction.Delete
|
||||||
{
|
{
|
||||||
private final Categories categories;
|
private final Categories categories;
|
||||||
|
|
||||||
@@ -58,4 +59,12 @@ public class CategoriesEntityResource implements EntityResourceAction.ReadById<C
|
|||||||
{
|
{
|
||||||
return categories.getCategoryById(id, parameters);
|
return categories.getCategoryById(id, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WebApiDescription(title = "Delete category",
|
||||||
|
description = "Delete a category given its node id",
|
||||||
|
successStatus = HttpServletResponse.SC_NO_CONTENT)
|
||||||
|
@Override
|
||||||
|
public void delete(String id, Parameters parameters) {
|
||||||
|
categories.deleteCategoryById(id, parameters);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -58,6 +58,7 @@ public class CategoriesImpl implements Categories
|
|||||||
{
|
{
|
||||||
static final String NOT_A_VALID_CATEGORY = "Node id does not refer to a valid category";
|
static final String NOT_A_VALID_CATEGORY = "Node id does not refer to a valid category";
|
||||||
static final String NO_PERMISSION_TO_CREATE_A_CATEGORY = "Current user does not have permission to create a category";
|
static final String NO_PERMISSION_TO_CREATE_A_CATEGORY = "Current user does not have permission to create a category";
|
||||||
|
static final String NO_PERMISSION_TO_DELETE_A_CATEGORY = "Current user does not have permission to delete a category";
|
||||||
private static final String NOT_NULL_OR_EMPTY = "Category name must not be null or empty";
|
private static final String NOT_NULL_OR_EMPTY = "Category name must not be null or empty";
|
||||||
|
|
||||||
private final AuthorityService authorityService;
|
private final AuthorityService authorityService;
|
||||||
@@ -114,6 +115,23 @@ public class CategoriesImpl implements Categories
|
|||||||
return ListPage.of(categories, params.getPaging());
|
return ListPage.of(categories, params.getPaging());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteCategoryById(String id, Parameters params)
|
||||||
|
{
|
||||||
|
if (!authorityService.hasAdminAuthority())
|
||||||
|
{
|
||||||
|
throw new PermissionDeniedException(NO_PERMISSION_TO_DELETE_A_CATEGORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
final NodeRef nodeRef = nodes.validateNode(id);
|
||||||
|
if (isNotACategory(nodeRef) || isRootCategory(nodeRef))
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeService.deleteNode(nodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method gets category NodeRef for a given category id.
|
* This method gets category NodeRef for a given category id.
|
||||||
* If '-root-' is passed as category id, then it's retrieved as a call to {@link org.alfresco.service.cmr.search.CategoryService#getRootCategoryNodeRef}
|
* If '-root-' is passed as category id, then it's retrieved as a call to {@link org.alfresco.service.cmr.search.CategoryService#getRootCategoryNodeRef}
|
||||||
|
@@ -230,6 +230,92 @@ public class CategoriesImplTest
|
|||||||
then(authorityServiceMock).shouldHaveNoInteractions();
|
then(authorityServiceMock).shouldHaveNoInteractions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCategoryById_asAdmin()
|
||||||
|
{
|
||||||
|
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
|
||||||
|
final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
|
||||||
|
given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
|
||||||
|
given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
|
||||||
|
final Node categoryNode = new Node();
|
||||||
|
categoryNode.setName(CATEGORY_NAME);
|
||||||
|
categoryNode.setNodeId(CATEGORY_ID);
|
||||||
|
final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
|
||||||
|
categoryNode.setParentId(parentNodeRef);
|
||||||
|
|
||||||
|
//when
|
||||||
|
objectUnderTest.deleteCategoryById(CATEGORY_ID, parametersMock);
|
||||||
|
|
||||||
|
then(authorityServiceMock).should().hasAdminAuthority();
|
||||||
|
then(authorityServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
then(nodesMock).should().validateNode(CATEGORY_ID);
|
||||||
|
|
||||||
|
then(nodesMock).should().isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false);
|
||||||
|
then(nodesMock).shouldHaveNoMoreInteractions();
|
||||||
|
|
||||||
|
then(nodeServiceMock).should().getParentAssocs(categoryNodeRef);
|
||||||
|
then(nodeServiceMock).should().deleteNode(categoryNodeRef);
|
||||||
|
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCategoryById_asNonAdminUser()
|
||||||
|
{
|
||||||
|
given(authorityServiceMock.hasAdminAuthority()).willReturn(false);
|
||||||
|
|
||||||
|
//when
|
||||||
|
assertThrows(PermissionDeniedException.class, () -> objectUnderTest.deleteCategoryById(CATEGORY_ID, parametersMock));
|
||||||
|
|
||||||
|
then(authorityServiceMock).should().hasAdminAuthority();
|
||||||
|
then(authorityServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
|
||||||
|
then(nodesMock).shouldHaveNoInteractions();
|
||||||
|
then(nodeServiceMock).shouldHaveNoInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCategoryById_nonCategoryId()
|
||||||
|
{
|
||||||
|
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
|
||||||
|
final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
|
||||||
|
given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
|
||||||
|
given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(false);
|
||||||
|
|
||||||
|
//when
|
||||||
|
assertThrows(InvalidArgumentException.class, () -> objectUnderTest.deleteCategoryById(CATEGORY_ID, parametersMock));
|
||||||
|
|
||||||
|
then(authorityServiceMock).should().hasAdminAuthority();
|
||||||
|
then(authorityServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
|
||||||
|
then(nodesMock).should().validateNode(CATEGORY_ID);
|
||||||
|
then(nodesMock).should().isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false);
|
||||||
|
then(nodesMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCategoryById_rootCategory()
|
||||||
|
{
|
||||||
|
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
|
||||||
|
final NodeRef categoryRootNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CAT_ROOT_NODE_ID);
|
||||||
|
given(nodesMock.validateNode(CAT_ROOT_NODE_ID)).willReturn(categoryRootNodeRef);
|
||||||
|
given(nodesMock.isSubClass(categoryRootNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
|
||||||
|
given(categoryChildAssociationRefMock.getQName()).willReturn(ContentModel.ASPECT_GEN_CLASSIFIABLE);
|
||||||
|
given(nodeServiceMock.getParentAssocs(categoryRootNodeRef)).willReturn(List.of(categoryChildAssociationRefMock));
|
||||||
|
|
||||||
|
//when
|
||||||
|
assertThrows(InvalidArgumentException.class, () -> objectUnderTest.deleteCategoryById(CAT_ROOT_NODE_ID, parametersMock));
|
||||||
|
|
||||||
|
then(authorityServiceMock).should().hasAdminAuthority();
|
||||||
|
then(authorityServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
|
||||||
|
then(nodesMock).should().validateNode(CAT_ROOT_NODE_ID);
|
||||||
|
then(nodesMock).should().isSubClass(categoryRootNodeRef, ContentModel.TYPE_CATEGORY, false);
|
||||||
|
then(nodesMock).shouldHaveNoMoreInteractions();
|
||||||
|
|
||||||
|
then(nodeServiceMock).should().getParentAssocs(categoryRootNodeRef);
|
||||||
|
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateCategoryUnderRoot()
|
public void testCreateCategoryUnderRoot()
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user