diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java index 27ed2f5bc7..33697d5a65 100644 --- a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java @@ -92,4 +92,16 @@ public class Categories extends ModelRequest 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); + } + } diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/DeleteCategoriesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/DeleteCategoriesTests.java new file mode 100644 index 0000000000..e0b11e582c --- /dev/null +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/DeleteCategoriesTests.java @@ -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 . + * #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; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/Categories.java b/remote-api/src/main/java/org/alfresco/rest/api/Categories.java index 7e03067e50..a3babc5905 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/Categories.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/Categories.java @@ -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.Parameters; import org.alfresco.service.Experimental; -import org.alfresco.service.cmr.repository.NodeRef; @Experimental public interface Categories @@ -42,4 +41,7 @@ public interface Categories List createSubcategories(String parentCategoryId, List categories, Parameters parameters); CollectionWithPagingInfo getCategoryChildren(String parentCategoryId, Parameters params); + + void deleteCategoryById(String id, Parameters params); + } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java b/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java index 3bde251ca0..df8483958f 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java @@ -41,7 +41,8 @@ import org.alfresco.rest.framework.resource.parameters.Parameters; * @author mpichura */ @EntityResource(name = "categories", title = "Categories") -public class CategoriesEntityResource implements EntityResourceAction.ReadById +public class CategoriesEntityResource implements EntityResourceAction.ReadById, + EntityResourceAction.Delete { private final Categories categories; @@ -58,4 +59,12 @@ public class CategoriesEntityResource implements EntityResourceAction.ReadById 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 public void testCreateCategoryUnderRoot() {