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));
+ }
}