From aa6c2601c7ce53d9bdee74e4800714eb1c3c7e0f Mon Sep 17 00:00:00 2001 From: milanmajchrak <90026355+milanmajchrak@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:10:31 +0200 Subject: [PATCH] ufal/be-collection2item-table-is-not-migrated (#439) * Created endpoint for importing item's mapped collections and created test for it * Fixed checkstyle issues * Fixed conflicts * refactoring * Refactoring according to request changes --- .../ClarinItemImportController.java | 97 ++++++++++++++++++- .../rest/ClarinItemImportControllerIT.java | 52 ++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java index 89f6a04d79bd..d37b54ab708c 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ClarinItemImportController.java @@ -8,8 +8,11 @@ package org.dspace.app.rest.repository; import static org.dspace.app.rest.utils.ContextUtil.obtainContext; +import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID; +import static org.dspace.core.Constants.COLLECTION; import java.io.IOException; +import java.io.InputStreamReader; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; @@ -20,6 +23,7 @@ import javax.servlet.http.HttpServletRequest; import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.converter.ConverterService; import org.dspace.app.rest.converter.MetadataConverter; @@ -27,10 +31,12 @@ import org.dspace.app.rest.exception.UnprocessableEntityException; import org.dspace.app.rest.model.ItemRest; import org.dspace.app.rest.model.WorkspaceItemRest; +import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.Utils; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Collection; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.content.WorkspaceItem; @@ -51,6 +57,8 @@ import org.dspace.workflow.WorkflowException; import org.dspace.xmlworkflow.service.XmlWorkflowService; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.json.simple.JSONArray; +import org.json.simple.parser.JSONParser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -366,6 +374,79 @@ public ItemRest importItem(HttpServletRequest request) throws SQLException, Auth return itemRest; } + /** + * Endpoint for importing item's mapped collection. + * The mapping for requested endpoint, for example + *
+     * {@code
+     * https:///api/clarin/import/item/{ITEM_UUID}/mappedCollections
+     * }
+     * 
+ * @param request request + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + @PreAuthorize("hasAuthority('ADMIN')") + @RequestMapping(method = RequestMethod.POST, value = "/item" + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + + "/mappedCollections") + public void importItemCollections(@PathVariable UUID uuid, HttpServletRequest request) throws SQLException, + AuthorizeException { + Context context = ContextUtil.obtainContext(request); + if (Objects.isNull(context)) { + throw new RuntimeException("Context is null - cannot import item's mapped collections."); + } + + // Load List of collection self links + List requestAsStringList = new ArrayList<>(); + JSONParser parser = new JSONParser(); + try { + Object obj = parser.parse(new InputStreamReader(request.getInputStream())); + + if (!(obj instanceof JSONArray)) { + throw new UnprocessableEntityException("The request is not a JSON Array"); + } + + for (Object entity : (JSONArray) obj) { + String collectionSelfLink = entity.toString(); + requestAsStringList.add(collectionSelfLink); + } + } catch (Exception e) { + throw new RuntimeException("Cannot import item's mapped collections because parsing of the request JSON" + + "throws this error: " + e.getMessage()); + } + + // Find Collections following its self link + List listDsoFoundInRequest + = utils.constructDSpaceObjectList(context, requestAsStringList); + + if (CollectionUtils.isEmpty(listDsoFoundInRequest)) { + throw new UnprocessableEntityException("Not a valid collection uuid."); + } + + for (DSpaceObject dso : listDsoFoundInRequest) { + + Item item = itemService.find(context, uuid); + if (dso != null && dso.getType() == COLLECTION && item != null) { + if (this.checkIfItemIsTemplate(item)) { + continue; + } + + Collection collectionToMapTo = (Collection) dso; + if (this.checkIfOwningCollection(item, collectionToMapTo.getID())) { + continue; + } + + collectionService.addItem(context, collectionToMapTo, item); + collectionService.update(context, collectionToMapTo); + itemService.update(context, item); + } else { + throw new UnprocessableEntityException("Not a valid collection or item uuid."); + } + } + + context.commit(); + } + /** * Convert String input value to boolean. * @param value input value @@ -391,4 +472,18 @@ private Integer getIntegerFromString(String value) { } return output; } -} \ No newline at end of file + + private boolean checkIfItemIsTemplate(Item item) { + return item.getTemplateItemOf() != null; + } + + private boolean checkIfOwningCollection(Item item, UUID collectionID) { + if (Objects.isNull(item)) { + return false; + } + if (Objects.isNull(item.getOwningCollection())) { + return false; + } + return item.getOwningCollection().getID().equals(collectionID); + } +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java index c8c6f5a9ce24..b561433b48c5 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ClarinItemImportControllerIT.java @@ -17,6 +17,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.UUID; @@ -33,6 +34,7 @@ import org.dspace.builder.WorkflowItemBuilder; import org.dspace.builder.WorkspaceItemBuilder; import org.dspace.content.Collection; +import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.content.WorkspaceItem; @@ -470,4 +472,54 @@ public void testImportAuthorityAndConfidenceInMetadata() throws Exception { assertEquals(dcRelationValue.getAuthority(), String.valueOf(AUTHORITY)); assertEquals(dcRelationValue.getConfidence(), CONFIDENCE); } + + @Test + public void importItemsMappedCollections() throws Exception { + context.turnOffAuthorisationSystem(); + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("Collection 3").build(); + + //2. Public item that is readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + context.restoreAuthSystemState(); + + String startOfCollectionLink = "https://localhost:8080/spring-rest/api/core/collections/"; + // It is owning collection + String col1SelfLink = startOfCollectionLink + col1.getID(); + String col2SelfLink = startOfCollectionLink + col2.getID(); + String col3SelfLink = startOfCollectionLink + col3.getID(); + List collectionSelfLinksList = new ArrayList<>(); + collectionSelfLinksList.add(col1SelfLink); + collectionSelfLinksList.add(col2SelfLink); + collectionSelfLinksList.add(col3SelfLink); + + ObjectMapper mapper = new ObjectMapper(); + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(post("/api/clarin/import/item/" + + publicItem1.getID() + "/mappedCollections") + .content(mapper.writeValueAsBytes(collectionSelfLinksList)) + .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + Item updatedItem = itemService.find(context, publicItem1.getID()); + assertEquals(updatedItem.getCollections().size(), 3); + assertTrue(updatedItem.getCollections().contains(col1)); + assertTrue(updatedItem.getCollections().contains(col2)); + assertTrue(updatedItem.getCollections().contains(col3)); + } }