From ad59842dd0c52986d028a32be6a013c20a3991a0 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Mon, 5 Aug 2019 13:41:26 +0200 Subject: [PATCH 01/23] Add endpoint to update collection harvest settings --- .../CollectionHarvestSettingsController.java | 96 +++++++++++++++++++ .../rest/model/HarvestedCollectionRest.java | 88 +++++++++++++++++ .../app/rest/model/HarvestedTypeEnum.java | 36 +++++++ ...CollectionHarvestSettingsControllerIT.java | 19 ++++ 4 files changed, 239 insertions(+) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java new file mode 100644 index 000000000000..77aadc8bdd32 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -0,0 +1,96 @@ +package org.dspace.app.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.logging.log4j.Logger; +import org.dspace.app.rest.exception.UnprocessableEntityException; +import org.dspace.app.rest.model.CollectionRest; +import org.dspace.app.rest.model.HarvestedCollectionRest; +import org.dspace.app.rest.model.HarvestedTypeEnum; +import org.dspace.content.Collection; +import org.dspace.content.service.CollectionService; +import org.dspace.core.Context; +import org.dspace.harvest.HarvestedCollection; +import org.dspace.harvest.service.HarvestedCollectionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import static org.dspace.core.Constants.COLLECTION; + +@RestController +@RequestMapping("/api/core/collections/" + + "{itemUuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12" + + "}}/harvester") +public class CollectionHarvestSettingsController { + + private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(CollectionHarvestSettingsController.class); + + @Autowired + CollectionService collectionService; + + @Autowired + HarvestedCollectionService harvestedCollectionService; + + @RequestMapping(method = RequestMethod.PUT, consumes = {"application/json"}) + @PreAuthorize("hasAuthority('ADMIN')") + public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, HttpServletResponse response, HttpServletRequest request) throws SQLException { + + Context context = new Context(); + Collection collection = collectionService.find(context, itemUuid); + + if (collection == null) { + throw new ResourceNotFoundException("Collection with uuid: " + itemUuid + " not found"); + } + + // Parse json into HarvestCollectionRest + ObjectMapper mapper = new ObjectMapper(); + HarvestedCollectionRest harvestedCollectionRest; + + try { + ServletInputStream input = request.getInputStream(); + harvestedCollectionRest = mapper.readValue(input, HarvestedCollectionRest.class); + } catch (IOException e) { + throw new UnprocessableEntityException("Error parsing request body: " + e.toString()); + } + + // Create a new harvestedCollection object if there isn't one yet + HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); + + if (harvestedCollection == null) { + harvestedCollection = harvestedCollectionService.create(context, collection); + } + + // Delete harvestedCollection object if harvest type is not set + if (harvestedCollectionRest.getHarvestType() == HarvestedTypeEnum.TYPE_NONE.getValue()) { + harvestedCollectionService.delete(context, harvestedCollection); + } + + updateCollectionHarvestSettings(harvestedCollection, harvestedCollectionRest); + context.complete(); + } + + public void updateCollectionHarvestSettings(HarvestedCollection harvestedCollection, + HarvestedCollectionRest harvestedCollectionRest) { + int harvestType = harvestedCollectionRest.getHarvestType(); + String oaiSource = harvestedCollectionRest.getOaiSource(); + String oaiSetId = harvestedCollectionRest.getOaiSetId(); + String metadataConfigId = harvestedCollectionRest.getMetadataConfigId(); + + harvestedCollection.setHarvestType(harvestType); + harvestedCollection.setOaiSource(oaiSource); + harvestedCollection.setOaiSetId(oaiSetId); + harvestedCollection.setHarvestMetadataConfig(metadataConfigId); + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java new file mode 100644 index 000000000000..05423bd76548 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java @@ -0,0 +1,88 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model; + +import com.fasterxml.jackson.annotation.*; +import org.dspace.app.rest.CollectionHarvestSettingsController; +import org.dspace.content.Collection; +import org.dspace.harvest.HarvestedCollection; + +import javax.persistence.Column; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; + +/** + * The HarvestCollection REST Resource + * + * @author Jelle Pelgrims (jelle.atmire at gmail.com) + */ +public class HarvestedCollectionRest extends BaseObjectRest { + + public static final String NAME = "harvestedCollection"; + public static final String CATEGORY = "core"; + + @JsonProperty("harvest_type") + private HarvestedTypeEnum harvestType; + + @JsonProperty("oai_source") + private String oaiSource; + + @JsonProperty("oai_set_id") + private String oaiSetId; + + @JsonProperty("metadata_config_id") + private String metadataConfigId; + + public String getCategory() { + return CATEGORY; + } + + public Class getController() { + return CollectionHarvestSettingsController.class; + } + + public String getType() { + return NAME; + } + + private Integer id; + private Collection collection; + + public int getHarvestType() { + return harvestType.ordinal(); + } + + public void setHarvestType(HarvestedTypeEnum harvestType) { + this.harvestType = harvestType; + } + + public String getOaiSource() { + return oaiSource; + } + + public void setOaiSource(String oaiSource) { + this.oaiSource = oaiSource; + } + + public String getOaiSetId() { + return oaiSetId; + } + + public void setOaiSetId(String oaiSetId) { + this.oaiSetId = oaiSetId; + } + + public String getMetadataConfigId() { + return metadataConfigId; + } + + public void setMetadataConfigId(String metadataConfigId) { + this.metadataConfigId = metadataConfigId; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java new file mode 100644 index 000000000000..aba183b50b1b --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java @@ -0,0 +1,36 @@ +package org.dspace.app.rest.model; + +import org.dspace.harvest.HarvestedCollection; + +public enum HarvestedTypeEnum { + TYPE_NONE(0), + METADATA_ONLY(1), + METADATA_AND_REF(2), + METADATA_AND_BITSTREAMS(3); + + private int harvestType; + + HarvestedTypeEnum(int harvestType) { + this.harvestType = harvestType; + } + + public int getValue() { + return harvestType; + } + + private HarvestedTypeEnum fromString(String harvestType) { + int type; + + /** if (harvestType.equals("METADATA_ONLY")) { + type = HarvestedCollection.TYPE_DMD; + } else if (harvestType.equals("METADATA_AND_REF")) { + type = HarvestedCollection.TYPE_DMDREF; + } else if (harvestType.equals("METADATA_AND_BITSTREAMS")) { + type = HarvestedCollection.TYPE_FULL; + } else { + throw new IllegalArgumentException(); + } **/ + + return HarvestedTypeEnum.valueOf(harvestType); + } +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java new file mode 100644 index 000000000000..3f3bdcc82ec0 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -0,0 +1,19 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.junit.Test; + +public class CollectionHarvestSettingsControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void test() throws Exception { + + } +} From 73865a904b3856e8b75e5bce77d8c6bbf9cbc1f5 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Mon, 5 Aug 2019 14:28:06 +0200 Subject: [PATCH 02/23] Refactor harvest settings endpoint after manual testing --- .../CollectionHarvestSettingsController.java | 28 ++++++++++--------- .../rest/model/HarvestedCollectionRest.java | 12 +------- .../app/rest/model/HarvestedTypeEnum.java | 20 +------------ 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 77aadc8bdd32..5f2299213d3d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -1,9 +1,15 @@ package org.dspace.app.rest; +import java.io.IOException; +import java.sql.SQLException; +import java.util.UUID; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.Logger; import org.dspace.app.rest.exception.UnprocessableEntityException; -import org.dspace.app.rest.model.CollectionRest; import org.dspace.app.rest.model.HarvestedCollectionRest; import org.dspace.app.rest.model.HarvestedTypeEnum; import org.dspace.content.Collection; @@ -19,15 +25,7 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; -import static org.dspace.core.Constants.COLLECTION; @RestController @RequestMapping("/api/core/collections/" + @@ -35,7 +33,8 @@ "}}/harvester") public class CollectionHarvestSettingsController { - private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(CollectionHarvestSettingsController.class); + private static final Logger log + = org.apache.logging.log4j.LogManager.getLogger(CollectionHarvestSettingsController.class); @Autowired CollectionService collectionService; @@ -45,7 +44,9 @@ public class CollectionHarvestSettingsController { @RequestMapping(method = RequestMethod.PUT, consumes = {"application/json"}) @PreAuthorize("hasAuthority('ADMIN')") - public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, HttpServletResponse response, HttpServletRequest request) throws SQLException { + public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, + HttpServletResponse response, + HttpServletRequest request) throws SQLException { Context context = new Context(); Collection collection = collectionService.find(context, itemUuid); @@ -73,11 +74,12 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, HttpServl } // Delete harvestedCollection object if harvest type is not set - if (harvestedCollectionRest.getHarvestType() == HarvestedTypeEnum.TYPE_NONE.getValue()) { + if (harvestedCollectionRest.getHarvestType() == HarvestedTypeEnum.NONE.getValue()) { harvestedCollectionService.delete(context, harvestedCollection); + } else { + updateCollectionHarvestSettings(harvestedCollection, harvestedCollectionRest); } - updateCollectionHarvestSettings(harvestedCollection, harvestedCollectionRest); context.complete(); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java index 05423bd76548..0d0cd582662b 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java @@ -7,15 +7,8 @@ */ package org.dspace.app.rest.model; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonProperty; import org.dspace.app.rest.CollectionHarvestSettingsController; -import org.dspace.content.Collection; -import org.dspace.harvest.HarvestedCollection; - -import javax.persistence.Column; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import java.util.Date; /** * The HarvestCollection REST Resource @@ -51,9 +44,6 @@ public String getType() { return NAME; } - private Integer id; - private Collection collection; - public int getHarvestType() { return harvestType.ordinal(); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java index aba183b50b1b..5a4dc29d7213 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java @@ -1,9 +1,7 @@ package org.dspace.app.rest.model; -import org.dspace.harvest.HarvestedCollection; - public enum HarvestedTypeEnum { - TYPE_NONE(0), + NONE(0), METADATA_ONLY(1), METADATA_AND_REF(2), METADATA_AND_BITSTREAMS(3); @@ -17,20 +15,4 @@ public enum HarvestedTypeEnum { public int getValue() { return harvestType; } - - private HarvestedTypeEnum fromString(String harvestType) { - int type; - - /** if (harvestType.equals("METADATA_ONLY")) { - type = HarvestedCollection.TYPE_DMD; - } else if (harvestType.equals("METADATA_AND_REF")) { - type = HarvestedCollection.TYPE_DMDREF; - } else if (harvestType.equals("METADATA_AND_BITSTREAMS")) { - type = HarvestedCollection.TYPE_FULL; - } else { - throw new IllegalArgumentException(); - } **/ - - return HarvestedTypeEnum.valueOf(harvestType); - } } From 0bb2135a8ecff38f5ed0613491df30ce1667b6f3 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Mon, 5 Aug 2019 15:41:28 +0200 Subject: [PATCH 03/23] Add Integration tests for harvest settings endpoint --- .../CollectionHarvestSettingsController.java | 4 +- ...stedTypeEnum.java => HarvestTypeEnum.java} | 4 +- .../rest/model/HarvestedCollectionRest.java | 4 +- ...CollectionHarvestSettingsControllerIT.java | 120 +++++++++++++++++- 4 files changed, 125 insertions(+), 7 deletions(-) rename dspace-server-webapp/src/main/java/org/dspace/app/rest/model/{HarvestedTypeEnum.java => HarvestTypeEnum.java} (78%) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 5f2299213d3d..eaa25b1944e2 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -11,7 +11,7 @@ import org.apache.logging.log4j.Logger; import org.dspace.app.rest.exception.UnprocessableEntityException; import org.dspace.app.rest.model.HarvestedCollectionRest; -import org.dspace.app.rest.model.HarvestedTypeEnum; +import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.content.Collection; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; @@ -74,7 +74,7 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, } // Delete harvestedCollection object if harvest type is not set - if (harvestedCollectionRest.getHarvestType() == HarvestedTypeEnum.NONE.getValue()) { + if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue()) { harvestedCollectionService.delete(context, harvestedCollection); } else { updateCollectionHarvestSettings(harvestedCollection, harvestedCollectionRest); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java similarity index 78% rename from dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java rename to dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java index 5a4dc29d7213..732605f3d4fd 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedTypeEnum.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java @@ -1,6 +1,6 @@ package org.dspace.app.rest.model; -public enum HarvestedTypeEnum { +public enum HarvestTypeEnum { NONE(0), METADATA_ONLY(1), METADATA_AND_REF(2), @@ -8,7 +8,7 @@ public enum HarvestedTypeEnum { private int harvestType; - HarvestedTypeEnum(int harvestType) { + HarvestTypeEnum(int harvestType) { this.harvestType = harvestType; } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java index 0d0cd582662b..e0bd19b7aa12 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java @@ -21,7 +21,7 @@ public class HarvestedCollectionRest extends BaseObjectRest { public static final String CATEGORY = "core"; @JsonProperty("harvest_type") - private HarvestedTypeEnum harvestType; + private HarvestTypeEnum harvestType; @JsonProperty("oai_source") private String oaiSource; @@ -48,7 +48,7 @@ public int getHarvestType() { return harvestType.ordinal(); } - public void setHarvestType(HarvestedTypeEnum harvestType) { + public void setHarvestType(HarvestTypeEnum harvestType) { this.harvestType = harvestType; } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index 3f3bdcc82ec0..e22164dabaa2 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -7,13 +7,131 @@ */ package org.dspace.app.rest; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.harvest.HarvestedCollection; +import org.dspace.harvest.service.HarvestedCollectionService; +import org.json.JSONObject; +import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; public class CollectionHarvestSettingsControllerIT extends AbstractControllerIntegrationTest { + Collection collection; + + @Autowired + HarvestedCollectionService harvestedCollectionService; + + @Before + public void SetUp() { + context.turnOffAuthorisationSystem(); + + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community community = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + collection = CollectionBuilder.createCollection(context, community).withName("Collection 1").build(); + + + + context.restoreAuthSystemState(); + } + + public JSONObject createHarvestSettingsJson(String harvestType, + String oaiSource, String oaiSetId, String metadataConfigId) { + JSONObject json = new JSONObject(); + json.put("harvest_type", harvestType); + json.put("oai_source", oaiSource); + json.put("oai_set_id", oaiSetId); + json.put("metadata_config_id", metadataConfigId); + return json; + } + @Test - public void test() throws Exception { + public void EndpointWorksWithStandardSettings() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.mit.edu/oai/request", "col_1721.1_114174", "dc"); + + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json") + .content(json.toString())) + .andExpect(status().isOk()); + + HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); + + assertTrue(harvestedCollection.getHarvestType() == HarvestTypeEnum.valueOf(json.getString("harvest_type")).getValue()); + assertTrue(harvestedCollection.getOaiSource().equals(json.getString("oai_source"))); + assertTrue(harvestedCollection.getOaiSetId().equals(json.getString("oai_set_id"))); + assertTrue(harvestedCollection.getHarvestMetadataConfig().equals(json.getString("metadata_config_id"))); + } + + @Test + public void HarvestSettingsDeletedIfHarvestTypeIsNone() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + JSONObject json = createHarvestSettingsJson("NONE", "", "", ""); + + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json") + .content(json.toString())) + .andExpect(status().isOk()); + + HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); + + assertNull(harvestedCollection); + } + + @Test + public void UnauthorizedIfNotAuthenticated() throws Exception { + getClient().perform(put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json")) + .andExpect(status().isUnauthorized()); + } + + @Test + public void ForbiddenIfNotEnoughpermissions() throws Exception { + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform(put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json")) + .andExpect(status().isForbidden()); + } + + @Test + public void NotFoundIfNoSuchCollection() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + String fakeUuid = "6c9a081e-f2e5-42cd-8cf8-338f64b0841b"; + getClient(token).perform(put("/api/core/collections/" + fakeUuid + "/harvester") + .contentType("application/json")) + .andExpect(status().isNotFound()); + } + + @Test + public void UnprocessableEntityIfHarvestTypeIncorrect() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + JSONObject json = createHarvestSettingsJson("INCORRECT_HARVEST_TYPE", "https://dspace.mit.edu/oai/request", "col_1721.1_114174", "dc"); + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json") + .content(json.toString())) + .andExpect(status().isUnprocessableEntity()); } } From 0c6f53758db78f26d80c393b4203dbe903511dc7 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Tue, 6 Aug 2019 08:48:54 +0200 Subject: [PATCH 04/23] Fix checkstyle errors --- .../dspace/app/rest/CollectionHarvestSettingsController.java | 2 +- .../dspace/app/rest/CollectionHarvestSettingsControllerIT.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index eaa25b1944e2..f1b925ad01f9 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -10,8 +10,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.Logger; import org.dspace.app.rest.exception.UnprocessableEntityException; -import org.dspace.app.rest.model.HarvestedCollectionRest; import org.dspace.app.rest.model.HarvestTypeEnum; +import org.dspace.app.rest.model.HarvestedCollectionRest; import org.dspace.content.Collection; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index e22164dabaa2..2e6454600b2c 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -73,7 +73,8 @@ public void EndpointWorksWithStandardSettings() throws Exception { HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); - assertTrue(harvestedCollection.getHarvestType() == HarvestTypeEnum.valueOf(json.getString("harvest_type")).getValue()); + assertTrue(harvestedCollection.getHarvestType() + == HarvestTypeEnum.valueOf(json.getString("harvest_type")).getValue()); assertTrue(harvestedCollection.getOaiSource().equals(json.getString("oai_source"))); assertTrue(harvestedCollection.getOaiSetId().equals(json.getString("oai_set_id"))); assertTrue(harvestedCollection.getHarvestMetadataConfig().equals(json.getString("metadata_config_id"))); From 251d264378af8fad0d04f5fae2c7a7f7a1026230 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Tue, 6 Aug 2019 11:56:31 +0200 Subject: [PATCH 05/23] Implemented changes --- .../CollectionHarvestSettingsController.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index f1b925ad01f9..1ac310088b9d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -8,10 +8,10 @@ import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.logging.log4j.Logger; import org.dspace.app.rest.exception.UnprocessableEntityException; import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.app.rest.model.HarvestedCollectionRest; +import org.dspace.app.rest.utils.ContextUtil; import org.dspace.content.Collection; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; @@ -29,13 +29,10 @@ @RestController @RequestMapping("/api/core/collections/" + - "{itemUuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12" + + "{collectionUuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12" + "}}/harvester") public class CollectionHarvestSettingsController { - private static final Logger log - = org.apache.logging.log4j.LogManager.getLogger(CollectionHarvestSettingsController.class); - @Autowired CollectionService collectionService; @@ -44,15 +41,15 @@ public class CollectionHarvestSettingsController { @RequestMapping(method = RequestMethod.PUT, consumes = {"application/json"}) @PreAuthorize("hasAuthority('ADMIN')") - public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, + public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, HttpServletResponse response, HttpServletRequest request) throws SQLException { - Context context = new Context(); - Collection collection = collectionService.find(context, itemUuid); + Context context = ContextUtil.obtainContext(request); + Collection collection = collectionService.find(context, collectionUuid); if (collection == null) { - throw new ResourceNotFoundException("Collection with uuid: " + itemUuid + " not found"); + throw new ResourceNotFoundException("Collection with uuid: " + collectionUuid + " not found"); } // Parse json into HarvestCollectionRest @@ -63,7 +60,7 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, ServletInputStream input = request.getInputStream(); harvestedCollectionRest = mapper.readValue(input, HarvestedCollectionRest.class); } catch (IOException e) { - throw new UnprocessableEntityException("Error parsing request body: " + e.toString()); + throw new UnprocessableEntityException("Error parsing request body: " + e.toString(), e); } // Create a new harvestedCollection object if there isn't one yet @@ -77,14 +74,14 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID itemUuid, if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue()) { harvestedCollectionService.delete(context, harvestedCollection); } else { - updateCollectionHarvestSettings(harvestedCollection, harvestedCollectionRest); + updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); } context.complete(); } - public void updateCollectionHarvestSettings(HarvestedCollection harvestedCollection, - HarvestedCollectionRest harvestedCollectionRest) { + private void updateCollectionHarvestSettings(Context context, HarvestedCollection harvestedCollection, + HarvestedCollectionRest harvestedCollectionRest) throws SQLException { int harvestType = harvestedCollectionRest.getHarvestType(); String oaiSource = harvestedCollectionRest.getOaiSource(); String oaiSetId = harvestedCollectionRest.getOaiSetId(); @@ -94,5 +91,7 @@ public void updateCollectionHarvestSettings(HarvestedCollection harvestedCollect harvestedCollection.setOaiSource(oaiSource); harvestedCollection.setOaiSetId(oaiSetId); harvestedCollection.setHarvestMetadataConfig(metadataConfigId); + + harvestedCollectionService.update(context, harvestedCollection); } } From 361f48bea17017cd3c12146a433fdac83fec7fe6 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Wed, 7 Aug 2019 09:58:50 +0200 Subject: [PATCH 06/23] Add settings verification to harvest settings endpoint --- .../CollectionHarvestSettingsController.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 1ac310088b9d..a5ca59411cef 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -16,6 +16,8 @@ import org.dspace.content.service.CollectionService; import org.dspace.core.Context; import org.dspace.harvest.HarvestedCollection; +import org.dspace.harvest.HarvestingException; +import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.service.HarvestedCollectionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.webmvc.ResourceNotFoundException; @@ -73,13 +75,25 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, // Delete harvestedCollection object if harvest type is not set if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue()) { harvestedCollectionService.delete(context, harvestedCollection); - } else { + } else if (testHarvestSettings(context, collection, harvestedCollection)) { updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); + } else { + throw new UnprocessableEntityException("Incorrect harvest settings in request"); } context.complete(); } + private boolean testHarvestSettings(Context context, Collection collection, HarvestedCollection harvestedCollection) + throws SQLException { + try { + OAIHarvester harvester = new OAIHarvester(context, collection, harvestedCollection); + return harvester.verifyOAIharvester().size() == 0; + } catch (HarvestingException e) { + return false; + } + } + private void updateCollectionHarvestSettings(Context context, HarvestedCollection harvestedCollection, HarvestedCollectionRest harvestedCollectionRest) throws SQLException { int harvestType = harvestedCollectionRest.getHarvestType(); From 07a8e33ab59bf5ce7e6e2c1b2baf89c259a41cc6 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Wed, 7 Aug 2019 10:34:18 +0200 Subject: [PATCH 07/23] Add integration test for harvest settings verification --- .../CollectionHarvestSettingsController.java | 18 ++++++++++-------- .../CollectionHarvestSettingsControllerIT.java | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index a5ca59411cef..a25faafb2969 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.sql.SQLException; +import java.util.List; import java.util.UUID; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; @@ -75,7 +76,7 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, // Delete harvestedCollection object if harvest type is not set if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue()) { harvestedCollectionService.delete(context, harvestedCollection); - } else if (testHarvestSettings(context, collection, harvestedCollection)) { + } else if (testHarvestSettings(context, collection, harvestedCollectionRest)) { updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); } else { throw new UnprocessableEntityException("Incorrect harvest settings in request"); @@ -84,14 +85,15 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, context.complete(); } - private boolean testHarvestSettings(Context context, Collection collection, HarvestedCollection harvestedCollection) + private boolean testHarvestSettings(Context context, Collection collection, HarvestedCollectionRest harvestedCollectionRest) throws SQLException { - try { - OAIHarvester harvester = new OAIHarvester(context, collection, harvestedCollection); - return harvester.verifyOAIharvester().size() == 0; - } catch (HarvestingException e) { - return false; - } + List errors = OAIHarvester.verifyOAIharvester( + harvestedCollectionRest.getOaiSource(), + harvestedCollectionRest.getOaiSetId(), + harvestedCollectionRest.getMetadataConfigId(), + true + ); + return errors.size() == 0; } private void updateCollectionHarvestSettings(Context context, HarvestedCollection harvestedCollection, diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index 2e6454600b2c..f4d35c2167c9 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -59,6 +59,8 @@ public JSONObject createHarvestSettingsJson(String harvestType, return json; } + + // This test might fail if the oai_source ("https://dspace.mit.edu/oai/request") is down @Test public void EndpointWorksWithStandardSettings() throws Exception { String token = getAuthToken(admin.getEmail(), password); @@ -80,6 +82,19 @@ public void EndpointWorksWithStandardSettings() throws Exception { assertTrue(harvestedCollection.getHarvestMetadataConfig().equals(json.getString("metadata_config_id"))); } + @Test + public void UnProcessableEntityIfIncorrectSettings() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.mit.edu/iao/request", "col_1721.1_114174", "bc"); + + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json") + .content(json.toString())) + .andExpect(status().isUnprocessableEntity()); + } + @Test public void HarvestSettingsDeletedIfHarvestTypeIsNone() throws Exception { String token = getAuthToken(admin.getEmail(), password); From 99bc1b7e0fd54192c7db6c396b2e1a1f7ad975fc Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Wed, 7 Aug 2019 14:12:37 +0200 Subject: [PATCH 08/23] Add endpoint for harvesting configurations --- .../java/org/dspace/harvest/OAIHarvester.java | 39 ++++++++++++++ .../CollectionHarvestSettingsController.java | 13 +++-- .../app/rest/HarvesterMetadataController.java | 53 +++++++++++++++++++ .../app/rest/model/HarvesterMetadataRest.java | 53 +++++++++++++++++++ .../hateoas/HarvesterMetadataResource.java | 19 +++++++ 5 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index 4e78729105cf..82aa7ec45a11 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -17,8 +17,12 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; +import java.util.Enumeration; import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; import java.util.List; import java.util.Locale; import java.util.Set; @@ -990,4 +994,39 @@ public static List verifyOAIharvester(String oaiSource, return errorSet; } + + public static List> getAvailableMetadataFormats() { + List> configs = new ArrayList<>(); + String metaString = "oai.harvester.metadataformats."; + Enumeration pe = Collections.enumeration( + DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys("oai") + ); + while (pe.hasMoreElements()) { + String key = (String) pe.nextElement(); + if (key.startsWith(metaString)) { + + String metadataString = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(key); + + String id = key.substring(metaString.length()); + String label; + String namespace = ""; + + if (metadataString.indexOf(',') != -1) { + label = metadataString.substring(metadataString.indexOf(',') + 1); + namespace = metadataString.substring(0, metadataString.indexOf(',')); + } else { + label = id + "(" + metadataString + ")"; + } + + Map config = new HashMap<>(); + config.put("id", id); + config.put("label", label); + config.put("namespace", namespace); + + configs.add(config); + } + } + + return configs; + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index a25faafb2969..05ef1d63831a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -1,3 +1,10 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ package org.dspace.app.rest; import java.io.IOException; @@ -17,7 +24,6 @@ import org.dspace.content.service.CollectionService; import org.dspace.core.Context; import org.dspace.harvest.HarvestedCollection; -import org.dspace.harvest.HarvestingException; import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.service.HarvestedCollectionService; import org.springframework.beans.factory.annotation.Autowired; @@ -85,8 +91,9 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, context.complete(); } - private boolean testHarvestSettings(Context context, Collection collection, HarvestedCollectionRest harvestedCollectionRest) - throws SQLException { + private boolean testHarvestSettings(Context context, + Collection collection, + HarvestedCollectionRest harvestedCollectionRest) throws SQLException { List errors = OAIHarvester.verifyOAIharvester( harvestedCollectionRest.getOaiSource(), harvestedCollectionRest.getOaiSetId(), diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java new file mode 100644 index 000000000000..dd223d796d8d --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java @@ -0,0 +1,53 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.dspace.app.rest.link.HalLinkService; +import org.dspace.app.rest.model.HarvesterMetadataRest; +import org.dspace.app.rest.model.hateoas.HarvesterMetadataResource; +import org.dspace.app.rest.utils.Utils; +import org.dspace.harvest.OAIHarvester; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + + + +@RestController +@RequestMapping("/api/config/harvestermetadata") +public class HarvesterMetadataController { + + @Autowired + private Utils utils; + + @Autowired + private HalLinkService halLinkService; + + @RequestMapping(method = RequestMethod.GET) + public HarvesterMetadataResource get(HttpServletRequest request, + HttpServletResponse response) { + List> configs = OAIHarvester.getAvailableMetadataFormats(); + + HarvesterMetadataRest data = new HarvesterMetadataRest(); + data.setConfigs(configs); + + HarvesterMetadataResource resource = new HarvesterMetadataResource(data, utils); + halLinkService.addLinks(resource); + + return resource; + } + + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java new file mode 100644 index 000000000000..a3c28c9ffecf --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java @@ -0,0 +1,53 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.dspace.app.rest.HarvesterMetadataController; + +public class HarvesterMetadataRest extends BaseObjectRest { + + public static final String NAME = "harvestermetadata"; + public static final String CATEGORY = RestAddressableModel.CONFIGURATION; + + private List> configs; + + @Override + @JsonIgnore + public String getId() { + return id; + } + + @JsonIgnore + public String getCategory() { + return CATEGORY; + } + + public Class getController() { + return HarvesterMetadataController.class; + } + + @JsonIgnore + public String getType() { + return NAME; + } + + public List> getConfigs() { + return configs; + } + + public void setConfigs(List> configs) { + this.configs = configs; + } + + + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java new file mode 100644 index 000000000000..76e891047424 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java @@ -0,0 +1,19 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import org.dspace.app.rest.model.HarvesterMetadataRest; +import org.dspace.app.rest.utils.Utils; + +public class HarvesterMetadataResource extends DSpaceResource { + + public HarvesterMetadataResource(HarvesterMetadataRest data, Utils utils, String... rels) { + super(data, utils, rels); + + } +} From 234ef08eac5ea6fc46e48fc65097799889efacc2 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Thu, 8 Aug 2019 09:25:00 +0200 Subject: [PATCH 09/23] Add integration test for harvester metadata format endpoint --- .../java/org/dspace/harvest/OAIHarvester.java | 4 +- .../rest/HarvesterMetadataControllerIT.java | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index 82aa7ec45a11..ab3a7bcf24a4 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -20,11 +20,11 @@ import java.util.Collections; import java.util.Date; import java.util.Enumeration; -import java.util.HashSet; import java.util.HashMap; -import java.util.Map; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.TimeZone; import javax.xml.parsers.ParserConfigurationException; diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java new file mode 100644 index 000000000000..bd4ec950542b --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java @@ -0,0 +1,38 @@ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.harvest.OAIHarvester; +import org.junit.Test; + + +public class HarvesterMetadataControllerIT extends AbstractControllerIntegrationTest { + + @Test + public void GetReturnsAllAvailableMetadataFormats() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + List> configs = OAIHarvester.getAvailableMetadataFormats(); + + Function> getAllValues = + key -> configs.stream().map(x -> x.get(key)).collect(Collectors.toList()); + + getClient(token).perform( + get("/api/config/harvestermetadata")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.configs[*].id", is(getAllValues.apply("id")))) + .andExpect(jsonPath("$.configs[*].label", is(getAllValues.apply("label")))) + .andExpect(jsonPath("$.configs[*].namespace", is(getAllValues.apply("namespace")))) + .andExpect(jsonPath("$._links.self.href", notNullValue())); + } +} From 38679befd8fce091bd6c1eac2f01fb869504b59c Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Fri, 9 Aug 2019 09:19:00 +0200 Subject: [PATCH 10/23] Implement fixes/tweaks and add javadocs --- .../java/org/dspace/app/harvest/Harvest.java | 4 +- .../HarvestedCollectionServiceImpl.java | 105 ++++++++++++++++ .../java/org/dspace/harvest/OAIHarvester.java | 115 +++-------------- .../service/HarvestedCollectionService.java | 11 ++ .../MockHarvestedCollectionServiceImpl.java | 30 +++++ .../CollectionHarvestSettingsController.java | 105 ++++++++++++---- .../app/rest/HarvesterMetadataController.java | 13 +- .../app/rest/model/HarvestTypeEnum.java | 13 ++ .../app/rest/model/HarvesterMetadataRest.java | 5 + .../hateoas/HarvesterMetadataResource.java | 6 + .../config/spring/api/core-services.xml | 116 ++++++++++++++++++ ...CollectionHarvestSettingsControllerIT.java | 21 +++- .../rest/HarvesterMetadataControllerIT.java | 6 +- .../MockHarvestedCollectionServiceImpl.java | 30 +++++ 14 files changed, 446 insertions(+), 134 deletions(-) create mode 100644 dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java create mode 100644 dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml create mode 100644 dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java diff --git a/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java b/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java index 3b324f2763f9..9ed3e742ce5d 100644 --- a/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java +++ b/dspace-api/src/main/java/org/dspace/app/harvest/Harvest.java @@ -460,7 +460,7 @@ private static void pingResponder(String server, String set, String metadataForm List errors; System.out.print("Testing basic PMH access: "); - errors = OAIHarvester.verifyOAIharvester(server, set, + errors = harvestedCollectionService.verifyOAIharvester(server, set, (null != metadataFormat) ? metadataFormat : "dc", false); if (errors.isEmpty()) { System.out.println("OK"); @@ -471,7 +471,7 @@ private static void pingResponder(String server, String set, String metadataForm } System.out.print("Testing ORE support: "); - errors = OAIHarvester.verifyOAIharvester(server, set, + errors = harvestedCollectionService.verifyOAIharvester(server, set, (null != metadataFormat) ? metadataFormat : "dc", true); if (errors.isEmpty()) { System.out.println("OK"); diff --git a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java index fadcfb6ea6a0..bb3057e0cd60 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/HarvestedCollectionServiceImpl.java @@ -7,16 +7,28 @@ */ package org.dspace.harvest; +import static org.dspace.harvest.OAIHarvester.OAI_ADDRESS_ERROR; +import static org.dspace.harvest.OAIHarvester.OAI_DMD_ERROR; +import static org.dspace.harvest.OAIHarvester.OAI_ORE_ERROR; +import static org.dspace.harvest.OAIHarvester.OAI_SET_ERROR; + import java.sql.SQLException; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; +import ORG.oclc.oai.harvester2.verb.Identify; +import ORG.oclc.oai.harvester2.verb.ListIdentifiers; import org.dspace.content.Collection; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.harvest.dao.HarvestedCollectionDAO; import org.dspace.harvest.service.HarvestedCollectionService; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Namespace; +import org.jdom.input.DOMBuilder; import org.springframework.beans.factory.annotation.Autowired; /** @@ -27,6 +39,10 @@ * @author kevinvandevelde at atmire.com */ public class HarvestedCollectionServiceImpl implements HarvestedCollectionService { + + private static final Namespace ORE_NS = Namespace.getNamespace("http://www.openarchives.org/ore/terms/"); + private static final Namespace OAI_NS = Namespace.getNamespace("http://www.openarchives.org/OAI/2.0/"); + @Autowired(required = true) protected HarvestedCollectionDAO harvestedCollectionDAO; @@ -156,5 +172,94 @@ public boolean exists(Context context) throws SQLException { return 0 < harvestedCollectionDAO.count(context); } + /** + * Verify the existence of an OAI server with the specified set and + * supporting the provided metadata formats. + * + * @param oaiSource the address of the OAI-PMH provider + * @param oaiSetId OAI set identifier + * @param metaPrefix OAI metadataPrefix + * @param testORE whether the method should also check the PMH provider for ORE support + * @return list of errors encountered during verification. Empty list indicates a "success" condition. + */ + public List verifyOAIharvester(String oaiSource, + String oaiSetId, String metaPrefix, boolean testORE) { + List errorSet = new ArrayList(); + + // First, see if we can contact the target server at all. + try { + new Identify(oaiSource); + } catch (Exception ex) { + errorSet.add(OAI_ADDRESS_ERROR + ": OAI server could not be reached."); + return errorSet; + } + + // Next, make sure the metadata we need is supported by the target server + Namespace DMD_NS = OAIHarvester.getDMDNamespace(metaPrefix); + if (null == DMD_NS) { + errorSet.add(OAI_DMD_ERROR + ": " + metaPrefix); + return errorSet; + } + + String OREOAIPrefix = null; + String DMDOAIPrefix = null; + + try { + OREOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, OAIHarvester.getORENamespace().getURI()); + DMDOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, DMD_NS.getURI()); + } catch (Exception ex) { + errorSet.add(OAI_ADDRESS_ERROR + + ": OAI did not respond to ListMetadataFormats query (" + + ORE_NS.getPrefix() + ":" + OREOAIPrefix + " ; " + + DMD_NS.getPrefix() + ":" + DMDOAIPrefix + "): " + + ex.getMessage()); + return errorSet; + } + + if (testORE && OREOAIPrefix == null) { + errorSet.add(OAI_ORE_ERROR + ": The OAI server does not support ORE dissemination"); + } + if (DMDOAIPrefix == null) { + errorSet.add(OAI_DMD_ERROR + ": The OAI server does not support dissemination in this format"); + } + + // Now scan the sets and make sure the one supplied is in the list + boolean foundSet = false; + try { + //If we do not want to harvest from one set, then skip this. + if (!"all".equals(oaiSetId)) { + ListIdentifiers ls = new ListIdentifiers(oaiSource, null, null, oaiSetId, DMDOAIPrefix); + + // The only error we can really get here is "noSetHierarchy" + if (ls.getErrors() != null && ls.getErrors().getLength() > 0) { + for (int i = 0; i < ls.getErrors().getLength(); i++) { + String errorCode = ls.getErrors().item(i).getAttributes().getNamedItem("code").getTextContent(); + errorSet.add( + OAI_SET_ERROR + ": The OAI server does not have a set with the specified setSpec (" + + errorCode + ")"); + } + } else { + // Drilling down to /OAI-PMH/ListSets/set + DOMBuilder db = new DOMBuilder(); + Document reply = db.build(ls.getDocument()); + Element root = reply.getRootElement(); + //Check if we can find items, if so this indicates that we have children and our sets exist + foundSet = 0 < root.getChild("ListIdentifiers", OAI_NS).getChildren().size(); + + if (!foundSet) { + errorSet.add(OAI_SET_ERROR + ": The OAI server does not have a set with the specified setSpec"); + } + } + } + } catch (RuntimeException re) { + throw re; + } catch (Exception e) { + errorSet.add(OAI_ADDRESS_ERROR + ": OAI server could not be reached"); + return errorSet; + } + + return errorSet; + } + } diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index ab3a7bcf24a4..bedf494adbab 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -32,7 +32,6 @@ import ORG.oclc.oai.harvester2.verb.GetRecord; import ORG.oclc.oai.harvester2.verb.Identify; -import ORG.oclc.oai.harvester2.verb.ListIdentifiers; import ORG.oclc.oai.harvester2.verb.ListMetadataFormats; import ORG.oclc.oai.harvester2.verb.ListRecords; import org.apache.commons.lang3.StringUtils; @@ -106,7 +105,7 @@ public class OAIHarvester { protected BitstreamFormatService bitstreamFormatService; protected BundleService bundleService; protected CollectionService collectionService; - protected HarvestedCollectionService harvestedCollection; + protected HarvestedCollectionService harvestedCollectionService; protected InstallItemService installItemService; protected ItemService itemService; protected HandleService handleService; @@ -144,7 +143,7 @@ public OAIHarvester(Context c, DSpaceObject dso, HarvestedCollection hc) throws bundleService = ContentServiceFactory.getInstance().getBundleService(); collectionService = ContentServiceFactory.getInstance().getCollectionService(); handleService = HandleServiceFactory.getInstance().getHandleService(); - harvestedCollection = HarvestServiceFactory.getInstance().getHarvestedCollectionService(); + harvestedCollectionService = HarvestServiceFactory.getInstance().getHarvestedCollectionService(); harvestedItemService = HarvestServiceFactory.getInstance().getHarvestedItemService(); itemService = ContentServiceFactory.getInstance().getItemService(); installItemService = ContentServiceFactory.getInstance().getInstallItemService(); @@ -154,7 +153,6 @@ public OAIHarvester(Context c, DSpaceObject dso, HarvestedCollection hc) throws configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); - if (dso.getType() != Constants.COLLECTION) { throw new HarvestingException("OAIHarvester can only harvest collections"); } @@ -163,7 +161,7 @@ public OAIHarvester(Context c, DSpaceObject dso, HarvestedCollection hc) throws targetCollection = (Collection) dso; harvestRow = hc; - if (harvestRow == null || !harvestedCollection.isHarvestable(harvestRow)) { + if (harvestRow == null || !harvestedCollectionService.isHarvestable(harvestRow)) { throw new HarvestingException("Provided collection is not set up for harvesting"); } @@ -192,7 +190,7 @@ public OAIHarvester(Context c, DSpaceObject dso, HarvestedCollection hc) throws * * @return Namespace of the supported ORE format. Returns null if not found. */ - private static Namespace getORENamespace() { + public static Namespace getORENamespace() { String ORESerializationString = null; String ORESeialKey = null; String oreString = "oai.harvester.oreSerializationFormat"; @@ -217,7 +215,7 @@ private static Namespace getORENamespace() { * @param metadataKey * @return Namespace of the designated metadata format. Returns null of not found. */ - private static Namespace getDMDNamespace(String metadataKey) { + public static Namespace getDMDNamespace(String metadataKey) { String metadataString = null; String metaString = "oai.harvester.metadataformats"; @@ -317,7 +315,7 @@ public void runHarvest() throws SQLException, IOException, AuthorizeException { harvestRow.setHarvestStatus(HarvestedCollection.STATUS_BUSY); harvestRow.setHarvestMessage("Collection harvesting is initializing..."); harvestRow.setHarvestStartTime(startTime); - harvestedCollection.update(ourContext, harvestRow); + harvestedCollectionService.update(ourContext, harvestRow); intermediateCommit(); // expiration timer starts @@ -358,7 +356,7 @@ public void runHarvest() throws SQLException, IOException, AuthorizeException { harvestRow.setHarvestStartTime(new Date()); harvestRow.setHarvestMessage("OAI server did not contain any updates"); harvestRow.setHarvestStatus(HarvestedCollection.STATUS_READY); - harvestedCollection.update(ourContext, harvestRow); + harvestedCollectionService.update(ourContext, harvestRow); return; } else { throw new HarvestingException(errorSet.toString()); @@ -415,7 +413,7 @@ public void runHarvest() throws SQLException, IOException, AuthorizeException { harvestRow.setHarvestMessage(String .format("Collection is currently being harvested (item %d of %d)", currentRecord, totalListSize)); - harvestedCollection.update(ourContext, harvestRow); + harvestedCollectionService.update(ourContext, harvestRow); } finally { //In case of an exception, make sure to restore our authentication state to the previous state ourContext.restoreAuthSystemState(); @@ -433,19 +431,19 @@ public void runHarvest() throws SQLException, IOException, AuthorizeException { alertAdmin(HarvestedCollection.STATUS_OAI_ERROR, hex); } harvestRow.setHarvestStatus(HarvestedCollection.STATUS_OAI_ERROR); - harvestedCollection.update(ourContext, harvestRow); + harvestedCollectionService.update(ourContext, harvestRow); ourContext.complete(); return; } catch (Exception ex) { harvestRow.setHarvestMessage("Unknown error occurred while generating an OAI response"); harvestRow.setHarvestStatus(HarvestedCollection.STATUS_UNKNOWN_ERROR); - harvestedCollection.update(ourContext, harvestRow); + harvestedCollectionService.update(ourContext, harvestRow); alertAdmin(HarvestedCollection.STATUS_UNKNOWN_ERROR, ex); log.error("Error occurred while generating an OAI response: " + ex.getMessage() + " " + ex.getCause(), ex); ourContext.complete(); return; } finally { - harvestedCollection.update(ourContext, harvestRow); + harvestedCollectionService.update(ourContext, harvestRow); ourContext.turnOffAuthorisationSystem(); collectionService.update(ourContext, targetCollection); ourContext.restoreAuthSystemState(); @@ -460,7 +458,7 @@ public void runHarvest() throws SQLException, IOException, AuthorizeException { log.info( "Harvest from " + oaiSource + " successful. The process took " + timeTaken + " milliseconds. Harvested " + currentRecord + " items."); - harvestedCollection.update(ourContext, harvestRow); + harvestedCollectionService.update(ourContext, harvestRow); ourContext.setMode(originalMode); } @@ -904,97 +902,14 @@ public List verifyOAIharvester() { String oaiSetId = harvestRow.getOaiSetId(); String metaPrefix = harvestRow.getHarvestMetadataConfig(); - return verifyOAIharvester(oaiSource, oaiSetId, metaPrefix, true); + return harvestedCollectionService.verifyOAIharvester(oaiSource, oaiSetId, metaPrefix, true); } /** - * Verify the existence of an OAI server with the specified set and - * supporting the provided metadata formats. + * Return all available metadata formats * - * @param oaiSource the address of the OAI-PMH provider - * @param oaiSetId OAI set identifier - * @param metaPrefix OAI metadataPrefix - * @param testORE whether the method should also check the PMH provider for ORE support - * @return list of errors encountered during verification. Empty list indicates a "success" condition. + * @return a list containing a map for each supported metadata format */ - public static List verifyOAIharvester(String oaiSource, - String oaiSetId, String metaPrefix, boolean testORE) { - List errorSet = new ArrayList(); - - // First, see if we can contact the target server at all. - try { - new Identify(oaiSource); - } catch (Exception ex) { - errorSet.add(OAI_ADDRESS_ERROR + ": OAI server could not be reached."); - return errorSet; - } - - // Next, make sure the metadata we need is supported by the target server - Namespace DMD_NS = OAIHarvester.getDMDNamespace(metaPrefix); - if (null == DMD_NS) { - errorSet.add(OAI_DMD_ERROR + ": " + metaPrefix); - return errorSet; - } - - String OREOAIPrefix = null; - String DMDOAIPrefix = null; - - try { - OREOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, getORENamespace().getURI()); - DMDOAIPrefix = OAIHarvester.oaiResolveNamespaceToPrefix(oaiSource, DMD_NS.getURI()); - } catch (Exception ex) { - errorSet.add(OAI_ADDRESS_ERROR - + ": OAI did not respond to ListMetadataFormats query (" - + ORE_NS.getPrefix() + ":" + OREOAIPrefix + " ; " - + DMD_NS.getPrefix() + ":" + DMDOAIPrefix + "): " - + ex.getMessage()); - return errorSet; - } - - if (testORE && OREOAIPrefix == null) { - errorSet.add(OAI_ORE_ERROR + ": The OAI server does not support ORE dissemination"); - } - if (DMDOAIPrefix == null) { - errorSet.add(OAI_DMD_ERROR + ": The OAI server does not support dissemination in this format"); - } - - // Now scan the sets and make sure the one supplied is in the list - boolean foundSet = false; - try { - //If we do not want to harvest from one set, then skip this. - if (!"all".equals(oaiSetId)) { - ListIdentifiers ls = new ListIdentifiers(oaiSource, null, null, oaiSetId, DMDOAIPrefix); - - // The only error we can really get here is "noSetHierarchy" - if (ls.getErrors() != null && ls.getErrors().getLength() > 0) { - for (int i = 0; i < ls.getErrors().getLength(); i++) { - String errorCode = ls.getErrors().item(i).getAttributes().getNamedItem("code").getTextContent(); - errorSet.add( - OAI_SET_ERROR + ": The OAI server does not have a set with the specified setSpec (" + - errorCode + ")"); - } - } else { - // Drilling down to /OAI-PMH/ListSets/set - Document reply = db.build(ls.getDocument()); - Element root = reply.getRootElement(); - //Check if we can find items, if so this indicates that we have children and our sets exist - foundSet = 0 < root.getChild("ListIdentifiers", OAI_NS).getChildren().size(); - - if (!foundSet) { - errorSet.add(OAI_SET_ERROR + ": The OAI server does not have a set with the specified setSpec"); - } - } - } - } catch (RuntimeException re) { - throw re; - } catch (Exception e) { - errorSet.add(OAI_ADDRESS_ERROR + ": OAI server could not be reached"); - return errorSet; - } - - return errorSet; - } - public static List> getAvailableMetadataFormats() { List> configs = new ArrayList<>(); String metaString = "oai.harvester.metadataformats."; diff --git a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java index 3b2220776f99..7df961a9c2ae 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java +++ b/dspace-api/src/main/java/org/dspace/harvest/service/HarvestedCollectionService.java @@ -137,4 +137,15 @@ public interface HarvestedCollectionService { public void update(Context context, HarvestedCollection harvestedCollection) throws SQLException; public boolean exists(Context context) throws SQLException; + + /** + * Test the given harvest settings + * @param oaiSource the address of the OAI-PMH provider + * @param oaiSetId OAI set identifier + * @param metaPrefix OAI metadataPrefix + * @param testORE whether the method should also check the PMH provider for ORE support + * @return list of errors encountered during verification. An empty list indicates a "success" condition. + */ + public List verifyOAIharvester(String oaiSource, + String oaiSetId, String metaPrefix, boolean testORE); } diff --git a/dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java b/dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java new file mode 100644 index 000000000000..1a1e3f40f6ed --- /dev/null +++ b/dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java @@ -0,0 +1,30 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.harvest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A mock for the HarvestedCollectionService + * @author Jelle Pelgrims (jelle.atmire at gmail.com) + */ +public class MockHarvestedCollectionServiceImpl extends HarvestedCollectionServiceImpl { + + @Override + public List verifyOAIharvester(String oaiSource, + String oaiSetId, String metaPrefix, boolean testORE) { + + if (metaPrefix.equals("dc")) { + return new ArrayList<>(); + } else { + return Arrays.asList("(Mock error) Incorrect metadataConfigID"); + } + } +} \ No newline at end of file diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 05ef1d63831a..28b795d06c17 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -9,7 +9,10 @@ import java.io.IOException; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.UUID; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; @@ -34,8 +37,11 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; - - +/** + * Rest controller that handles the changing of harvest settings for collections + * + * @author Jelle Pelgrims + */ @RestController @RequestMapping("/api/core/collections/" + "{collectionUuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12" + @@ -48,6 +54,14 @@ public class CollectionHarvestSettingsController { @Autowired HarvestedCollectionService harvestedCollectionService; + /** + * GET Endpoint for updating the settings of a collection. + * + * @param collectionUuid The collection whose settings should be changed + * @param response The response object + * @param request The request object + * @throws SQLException + */ @RequestMapping(method = RequestMethod.PUT, consumes = {"application/json"}) @PreAuthorize("hasAuthority('ADMIN')") public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, @@ -72,37 +86,82 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, throw new UnprocessableEntityException("Error parsing request body: " + e.toString(), e); } - // Create a new harvestedCollection object if there isn't one yet HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); - if (harvestedCollection == null) { - harvestedCollection = harvestedCollectionService.create(context, collection); - } - - // Delete harvestedCollection object if harvest type is not set - if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue()) { + // Delete harvestedCollectionService object if harvest type is not set + if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue() + && harvestedCollection != null) { harvestedCollectionService.delete(context, harvestedCollection); - } else if (testHarvestSettings(context, collection, harvestedCollectionRest)) { - updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); - } else { - throw new UnprocessableEntityException("Incorrect harvest settings in request"); + + } else if (harvestedCollectionRest.getHarvestType() != HarvestTypeEnum.NONE.getValue()) { + List errors = testHarvestSettings(collection, harvestedCollectionRest); + + if (errors.size() == 0) { + if (harvestedCollection == null) { + harvestedCollection = harvestedCollectionService.create(context, collection); + } + + updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); + } else { + throw new UnprocessableEntityException( + "Incorrect harvest settings in request. The following errors were found: " + errors.toString() + ); + } } context.complete(); } - private boolean testHarvestSettings(Context context, - Collection collection, - HarvestedCollectionRest harvestedCollectionRest) throws SQLException { - List errors = OAIHarvester.verifyOAIharvester( - harvestedCollectionRest.getOaiSource(), - harvestedCollectionRest.getOaiSetId(), - harvestedCollectionRest.getMetadataConfigId(), - true - ); - return errors.size() == 0; + /** + * Function used to verify that the harvest settings work + * @param collection The collection to which the harvest settings should be aplied + * @param harvestedCollectionRest A object containg the harvest settings to be tested + * @return + */ + private List testHarvestSettings(Collection collection, + HarvestedCollectionRest harvestedCollectionRest) { + + int harvestType = harvestedCollectionRest.getHarvestType(); + String metadataConfigId = harvestedCollectionRest.getMetadataConfigId(); + + List errors = new ArrayList<>(); + + // See if metadata config identifier appears in available metadata formats + List> metadataFormats = OAIHarvester.getAvailableMetadataFormats(); + boolean inAvailableMetadataFormats = metadataFormats.stream() + .filter(x -> x.get("id").equals(metadataConfigId)) + .count() >= 1; + + if (inAvailableMetadataFormats) { + boolean testORE = Arrays.asList( + HarvestTypeEnum.METADATA_AND_REF.getValue(), + HarvestTypeEnum.METADATA_AND_BITSTREAMS.getValue() + ).contains(harvestType); + + // Actually verify the harvest settings + List verificationErrors = harvestedCollectionService.verifyOAIharvester( + harvestedCollectionRest.getOaiSource(), + harvestedCollectionRest.getOaiSetId(), + metadataConfigId, + testORE + ); + errors = verificationErrors; + } else { + errors.add( + "The metadata format with identifier '" + metadataConfigId + "' is not an available metadata format." + ); + } + + return errors; } + /** + * Function to update the harvest settings of a collection + * @param context The context object + * @param harvestedCollection The harvestedCollection whose settings should be updated + * @param harvestedCollectionRest An object containing the new harvest settings + * @throws SQLException + */ private void updateCollectionHarvestSettings(Context context, HarvestedCollection harvestedCollection, HarvestedCollectionRest harvestedCollectionRest) throws SQLException { int harvestType = harvestedCollectionRest.getHarvestType(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java index dd223d796d8d..a07eaab6c229 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java @@ -23,8 +23,11 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; - - +/** + * Rest controller that handles the harvesting metadata formats + * + * @author Jelle Pelgrims + */ @RestController @RequestMapping("/api/config/harvestermetadata") public class HarvesterMetadataController { @@ -35,6 +38,12 @@ public class HarvesterMetadataController { @Autowired private HalLinkService halLinkService; + /** + * GET endpoint that returns all available metadata formats + * @param request The request object + * @param response The response object + * @return a HarvesterMetadataResource containing all available metadata formats + */ @RequestMapping(method = RequestMethod.GET) public HarvesterMetadataResource get(HttpServletRequest request, HttpServletResponse response) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java index 732605f3d4fd..aa9f24a4b61b 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java @@ -1,5 +1,18 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + package org.dspace.app.rest.model; +/** + * An enum containing all the possible harvest types + * + * @author Jelle Pelgrims (jelle.atmire @ gmail.com) + */ public enum HarvestTypeEnum { NONE(0), METADATA_ONLY(1), diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java index a3c28c9ffecf..1b1e428e2cb9 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java @@ -13,6 +13,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.dspace.app.rest.HarvesterMetadataController; +/** + * The rest resource used for harvester metadata + * + * @author Jelle Pelgrims + */ public class HarvesterMetadataRest extends BaseObjectRest { public static final String NAME = "harvestermetadata"; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java index 76e891047424..6cc64c498d0a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java @@ -10,6 +10,12 @@ import org.dspace.app.rest.model.HarvesterMetadataRest; import org.dspace.app.rest.utils.Utils; +/** + * Harvester metadata rest HAL Resource. The HAL Resource wraps the REST Resource + * adding support for the links. + * + * @author Jelle Pelgrims (jelle.pelgrims at gmail.com) + */ public class HarvesterMetadataResource extends DSpaceResource { public HarvesterMetadataResource(HarvesterMetadataRest data, Utils utils, String... rels) { diff --git a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml new file mode 100644 index 000000000000..b58f7db043d7 --- /dev/null +++ b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + news-top.html + news-side.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index f4d35c2167c9..25f31d1354e4 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -25,6 +25,11 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +/** + * Integration test for collection harvest settings controller + * + * @author Jelle Pelgrims (jelle.atmire at gmail.com) + */ public class CollectionHarvestSettingsControllerIT extends AbstractControllerIntegrationTest { Collection collection; @@ -44,11 +49,17 @@ public void SetUp() { .build(); collection = CollectionBuilder.createCollection(context, community).withName("Collection 1").build(); - - context.restoreAuthSystemState(); } + /** + * Function to create a JSONObject containing the harvest settings + * @param harvestType The harvest type + * @param oaiSource The OAI source + * @param oaiSetId The OAI set id + * @param metadataConfigId The metadata config id + * @return A JSONObject containing the given harvest settings + */ public JSONObject createHarvestSettingsJson(String harvestType, String oaiSource, String oaiSetId, String metadataConfigId) { JSONObject json = new JSONObject(); @@ -59,13 +70,11 @@ public JSONObject createHarvestSettingsJson(String harvestType, return json; } - - // This test might fail if the oai_source ("https://dspace.mit.edu/oai/request") is down @Test public void EndpointWorksWithStandardSettings() throws Exception { String token = getAuthToken(admin.getEmail(), password); - JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.mit.edu/oai/request", "col_1721.1_114174", "dc"); + JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.org/oai/request", "col_1721.1_114174", "dc"); getClient(token).perform( put("/api/core/collections/" + collection.getID() + "/harvester") @@ -99,7 +108,7 @@ public void UnProcessableEntityIfIncorrectSettings() throws Exception { public void HarvestSettingsDeletedIfHarvestTypeIsNone() throws Exception { String token = getAuthToken(admin.getEmail(), password); - JSONObject json = createHarvestSettingsJson("NONE", "", "", ""); + JSONObject json = createHarvestSettingsJson("NONE", "", "", "dc"); getClient(token).perform( put("/api/core/collections/" + collection.getID() + "/harvester") diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java index bd4ec950542b..c12a17948b8a 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java @@ -15,7 +15,11 @@ import org.dspace.harvest.OAIHarvester; import org.junit.Test; - +/** + * Integration test for harvester metadata controller + * + * @author Jelle Pelgrims (jelle.atmire at gmail.com) + */ public class HarvesterMetadataControllerIT extends AbstractControllerIntegrationTest { @Test diff --git a/dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java b/dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java new file mode 100644 index 000000000000..1a1e3f40f6ed --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java @@ -0,0 +1,30 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.harvest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A mock for the HarvestedCollectionService + * @author Jelle Pelgrims (jelle.atmire at gmail.com) + */ +public class MockHarvestedCollectionServiceImpl extends HarvestedCollectionServiceImpl { + + @Override + public List verifyOAIharvester(String oaiSource, + String oaiSetId, String metaPrefix, boolean testORE) { + + if (metaPrefix.equals("dc")) { + return new ArrayList<>(); + } else { + return Arrays.asList("(Mock error) Incorrect metadataConfigID"); + } + } +} \ No newline at end of file From d401af5f99e5bcd5f1277ecc8ce74db404faea01 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Fri, 9 Aug 2019 09:36:02 +0200 Subject: [PATCH 11/23] Update javadoc author tag email --- .../org/dspace/harvest/MockHarvestedCollectionServiceImpl.java | 2 +- .../dspace/app/rest/CollectionHarvestSettingsController.java | 2 +- .../java/org/dspace/app/rest/HarvesterMetadataController.java | 2 +- .../main/java/org/dspace/app/rest/model/HarvestTypeEnum.java | 2 +- .../java/org/dspace/app/rest/model/HarvestedCollectionRest.java | 2 +- .../java/org/dspace/app/rest/model/HarvesterMetadataRest.java | 2 +- .../app/rest/model/hateoas/HarvesterMetadataResource.java | 2 +- .../dspace/app/rest/CollectionHarvestSettingsControllerIT.java | 2 +- .../java/org/dspace/app/rest/HarvesterMetadataControllerIT.java | 2 +- .../org/dspace/harvest/MockHarvestedCollectionServiceImpl.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java b/dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java index 1a1e3f40f6ed..50793ed05337 100644 --- a/dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java +++ b/dspace-api/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java @@ -13,7 +13,7 @@ /** * A mock for the HarvestedCollectionService - * @author Jelle Pelgrims (jelle.atmire at gmail.com) + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public class MockHarvestedCollectionServiceImpl extends HarvestedCollectionServiceImpl { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 28b795d06c17..2897f72cc0c1 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -40,7 +40,7 @@ /** * Rest controller that handles the changing of harvest settings for collections * - * @author Jelle Pelgrims + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ @RestController @RequestMapping("/api/core/collections/" + diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java index a07eaab6c229..d9a85ac6beda 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java @@ -26,7 +26,7 @@ /** * Rest controller that handles the harvesting metadata formats * - * @author Jelle Pelgrims + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ @RestController @RequestMapping("/api/config/harvestermetadata") diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java index aa9f24a4b61b..9c8ac3689cf5 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java @@ -11,7 +11,7 @@ /** * An enum containing all the possible harvest types * - * @author Jelle Pelgrims (jelle.atmire @ gmail.com) + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public enum HarvestTypeEnum { NONE(0), diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java index e0bd19b7aa12..ca2c142d4eef 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java @@ -13,7 +13,7 @@ /** * The HarvestCollection REST Resource * - * @author Jelle Pelgrims (jelle.atmire at gmail.com) + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public class HarvestedCollectionRest extends BaseObjectRest { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java index 1b1e428e2cb9..a160a221b639 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java @@ -16,7 +16,7 @@ /** * The rest resource used for harvester metadata * - * @author Jelle Pelgrims + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public class HarvesterMetadataRest extends BaseObjectRest { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java index 6cc64c498d0a..ec08e398fd17 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java @@ -14,7 +14,7 @@ * Harvester metadata rest HAL Resource. The HAL Resource wraps the REST Resource * adding support for the links. * - * @author Jelle Pelgrims (jelle.pelgrims at gmail.com) + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public class HarvesterMetadataResource extends DSpaceResource { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index 25f31d1354e4..68dfb0564952 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -28,7 +28,7 @@ /** * Integration test for collection harvest settings controller * - * @author Jelle Pelgrims (jelle.atmire at gmail.com) + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public class CollectionHarvestSettingsControllerIT extends AbstractControllerIntegrationTest { diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java index c12a17948b8a..e1e235c22a06 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java @@ -18,7 +18,7 @@ /** * Integration test for harvester metadata controller * - * @author Jelle Pelgrims (jelle.atmire at gmail.com) + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public class HarvesterMetadataControllerIT extends AbstractControllerIntegrationTest { diff --git a/dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java b/dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java index 1a1e3f40f6ed..50793ed05337 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java +++ b/dspace-server-webapp/src/test/java/org/dspace/harvest/MockHarvestedCollectionServiceImpl.java @@ -13,7 +13,7 @@ /** * A mock for the HarvestedCollectionService - * @author Jelle Pelgrims (jelle.atmire at gmail.com) + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ public class MockHarvestedCollectionServiceImpl extends HarvestedCollectionServiceImpl { From d2470286a6de7ff2c2263d219615daafb61265c6 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Tue, 13 Aug 2019 12:44:48 +0200 Subject: [PATCH 12/23] Add endpoint to retrieve collection harvest settings --- .../java/org/dspace/harvest/OAIHarvester.java | 2 +- .../CollectionHarvestSettingsController.java | 49 ++++++++- .../app/rest/HarvesterMetadataController.java | 2 +- .../HarvestedCollectionConverter.java | 82 ++++++++++++++ .../HarvestedCollectionHalLinkFactory.java | 44 ++++++++ ...HarvestedCollectionRestHalLinkFactory.java | 20 ++++ .../app/rest/model/HarvestStatusEnum.java | 47 ++++++++ .../app/rest/model/HarvestTypeEnum.java | 20 +++- .../rest/model/HarvestedCollectionRest.java | 98 ++++++++++++++++- .../app/rest/model/HarvesterMetadataRest.java | 20 ++-- .../hateoas/HarvestedCollectionResource.java | 37 +++++++ .../hateoas/HarvesterMetadataResource.java | 6 +- .../HarvestedCollectionRestRepository.java | 50 +++++++++ .../HarvesterMetadataRestRepository.java | 42 ++++++++ ...CollectionHarvestSettingsControllerIT.java | 101 ++++++++++++++++-- .../rest/HarvesterMetadataControllerIT.java | 25 +++-- .../rest/matcher/MetadataConfigsMatcher.java | 48 +++++++++ 17 files changed, 652 insertions(+), 41 deletions(-) create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/HarvestedCollectionConverter.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionHalLinkFactory.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionRestHalLinkFactory.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestStatusEnum.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/MetadataConfigsMatcher.java diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index bedf494adbab..0202ab5dfa51 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -927,7 +927,7 @@ public static List> getAvailableMetadataFormats() { String namespace = ""; if (metadataString.indexOf(',') != -1) { - label = metadataString.substring(metadataString.indexOf(',') + 1); + label = metadataString.substring(metadataString.indexOf(',') + 2); namespace = metadataString.substring(0, metadataString.indexOf(',')); } else { label = id + "(" + metadataString + ")"; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 2897f72cc0c1..ae103213e10d 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -20,9 +20,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.dspace.app.rest.exception.UnprocessableEntityException; +import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.app.rest.model.HarvestedCollectionRest; +import org.dspace.app.rest.model.hateoas.HarvestedCollectionResource; +import org.dspace.app.rest.repository.HarvestedCollectionRestRepository; import org.dspace.app.rest.utils.ContextUtil; +import org.dspace.app.rest.utils.Utils; import org.dspace.content.Collection; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; @@ -38,7 +42,7 @@ import org.springframework.web.bind.annotation.RestController; /** - * Rest controller that handles the changing of harvest settings for collections + * Rest controller that handles the harvest settings for collections * * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ @@ -54,12 +58,49 @@ public class CollectionHarvestSettingsController { @Autowired HarvestedCollectionService harvestedCollectionService; + @Autowired + private HalLinkService halLinkService; + + @Autowired + HarvestedCollectionRestRepository harvestedCollectionRestRepository; + + @Autowired + private Utils utils; + + /** + * GET endpoint that returns the harvest settings of the given collection + * @param request The request object + * @param response The response object + * @return a HarvesterMetadataResource containing all available metadata formats + */ + @PreAuthorize("hasAuthority('ADMIN')") + @RequestMapping(method = RequestMethod.GET) + public HarvestedCollectionResource get(@PathVariable UUID collectionUuid, + HttpServletRequest request, + HttpServletResponse response) throws SQLException { + + Context context = ContextUtil.obtainContext(request); + Collection collection = collectionService.find(context, collectionUuid); + + if (collection == null) { + throw new ResourceNotFoundException("Collection with uuid: " + collectionUuid + " not found"); + } + + HarvestedCollectionRest harvestedCollectionRest = harvestedCollectionRestRepository.findOne(collection); + HarvestedCollectionResource resource = new HarvestedCollectionResource(harvestedCollectionRest); + + halLinkService.addLinks(resource); + + return resource; + } + + /** - * GET Endpoint for updating the settings of a collection. + * PUT Endpoint for updating the settings of a collection. * * @param collectionUuid The collection whose settings should be changed - * @param response The response object - * @param request The request object + * @param response The response object + * @param request The request object * @throws SQLException */ @RequestMapping(method = RequestMethod.PUT, consumes = {"application/json"}) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java index d9a85ac6beda..121f886fff31 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/HarvesterMetadataController.java @@ -33,7 +33,7 @@ public class HarvesterMetadataController { @Autowired - private Utils utils; + Utils utils; @Autowired private HalLinkService halLinkService; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/HarvestedCollectionConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/HarvestedCollectionConverter.java new file mode 100644 index 000000000000..e3176d756305 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/HarvestedCollectionConverter.java @@ -0,0 +1,82 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.converter; + +import java.util.List; +import java.util.Map; + +import org.dspace.app.rest.model.HarvestStatusEnum; +import org.dspace.app.rest.model.HarvestTypeEnum; +import org.dspace.app.rest.model.HarvestedCollectionRest; +import org.dspace.app.rest.model.HarvesterMetadataRest; +import org.dspace.content.Collection; +import org.dspace.harvest.HarvestedCollection; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import sun.reflect.generics.reflectiveObjects.NotImplementedException; + +/** + * This is the converter from/to the HarvestedCollection in the DSpace API data model and the REST data model + * + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) + */ +@Component +public class HarvestedCollectionConverter implements DSpaceConverter { + + @Autowired + private CollectionConverter collectionConverter; + + @Override + public HarvestedCollectionRest fromModel(HarvestedCollection obj) { + HarvestedCollectionRest harvestedCollectionRest = new HarvestedCollectionRest(); + + if (obj != null) { + HarvestTypeEnum harvestTypeEnum = HarvestTypeEnum.fromInt(obj.getHarvestType()); + HarvestStatusEnum harvestStatusEnum = HarvestStatusEnum.fromInt(obj.getHarvestStatus()); + + harvestedCollectionRest.setId(obj.getID()); + harvestedCollectionRest.setCollection(collectionConverter.fromModel(obj.getCollection())); + harvestedCollectionRest.setHarvestType(harvestTypeEnum); + harvestedCollectionRest.setHarvestStatus(harvestStatusEnum); + harvestedCollectionRest.setMetadataConfigId(obj.getHarvestMetadataConfig()); + harvestedCollectionRest.setOaiSetId(obj.getOaiSetId()); + harvestedCollectionRest.setOaiSource(obj.getOaiSource()); + harvestedCollectionRest.setHarvestMessage(obj.getHarvestMessage()); + harvestedCollectionRest.setHarvestStartTime(obj.getHarvestStartTime()); + harvestedCollectionRest.setLastHarvested(obj.getHarvestDate()); + } else { + harvestedCollectionRest.setHarvestType(HarvestTypeEnum.NONE); + } + + return harvestedCollectionRest; + + } + + public HarvestedCollectionRest fromModel(HarvestedCollection obj, + Collection collection, + List> metadata_configs) { + HarvestedCollectionRest harvestedCollectionRest = this.fromModel(obj); + + // Add collectionRest to the empty HarvestedCollectionRest so that we can use its uuid later in the linkFactory + if (obj == null) { + harvestedCollectionRest.setCollection(collectionConverter.fromModel(collection)); + } + + HarvesterMetadataRest harvesterMetadataRest = new HarvesterMetadataRest(); + harvesterMetadataRest.setConfigs(metadata_configs); + + harvestedCollectionRest.setMetadataConfigs(harvesterMetadataRest); + + return harvestedCollectionRest; + } + + @Override + public HarvestedCollection toModel(HarvestedCollectionRest obj) { + throw new NotImplementedException(); + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionHalLinkFactory.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionHalLinkFactory.java new file mode 100644 index 000000000000..12b3f89f3d4d --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionHalLinkFactory.java @@ -0,0 +1,44 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.link.harvest; + +import java.util.LinkedList; +import java.util.UUID; + +import org.dspace.app.rest.model.HarvestedCollectionRest; +import org.dspace.app.rest.model.hateoas.HarvestedCollectionResource; +import org.springframework.data.domain.Pageable; +import org.springframework.hateoas.Link; +import org.springframework.stereotype.Component; + +/** + * This class adds links to {@link org.dspace.app.rest.model.hateoas.HarvestedCollectionResource}s + * This builds a link to the collection harvest link + */ +@Component +public class HarvestedCollectionHalLinkFactory + extends HarvestedCollectionRestHalLinkFactory { + + protected void addLinks(HarvestedCollectionResource halResource, Pageable page, LinkedList list) + throws Exception { + HarvestedCollectionRest data = halResource.getContent(); + + if (data != null) { + list.add( + buildLink( + Link.REL_SELF, + getMethodOn().get(UUID.fromString(data.getCollectionRest().getUuid()), null, null) + ) + ); + } + } + + protected Class getResourceClass() { + return HarvestedCollectionResource.class; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionRestHalLinkFactory.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionRestHalLinkFactory.java new file mode 100644 index 000000000000..027a5358466e --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/harvest/HarvestedCollectionRestHalLinkFactory.java @@ -0,0 +1,20 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.link.harvest; + +import org.dspace.app.rest.CollectionHarvestSettingsController; +import org.dspace.app.rest.link.HalLinkFactory; + +public abstract class HarvestedCollectionRestHalLinkFactory + extends HalLinkFactory { + + @Override + protected Class getControllerClass() { + return CollectionHarvestSettingsController.class; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestStatusEnum.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestStatusEnum.java new file mode 100644 index 000000000000..9d8e9264e2d7 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestStatusEnum.java @@ -0,0 +1,47 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.app.rest.model; + +/** + * An enum containing all the possible harvest statuses + * + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) + */ +public enum HarvestStatusEnum { + READY(0), + BUSY(1), + QUEUED(2), + OAI_ERROR(3), + UNKNOWN_ERROR(-1); + + private int harvestStatus; + + HarvestStatusEnum(int harvestStatus) { + this.harvestStatus = harvestStatus; + } + + public int getValue() { + return harvestStatus; + } + + public static HarvestStatusEnum fromInt(Integer harvestStatus) { + if (harvestStatus == null) { + return null; + } + + switch (harvestStatus) { + case -1: return HarvestStatusEnum.UNKNOWN_ERROR; + case 0: return HarvestStatusEnum.READY; + case 1: return HarvestStatusEnum.BUSY; + case 2: return HarvestStatusEnum.QUEUED; + case 3: return HarvestStatusEnum.OAI_ERROR; + default: throw new IllegalArgumentException("No corresponding enum value for integer"); + } + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java index 9c8ac3689cf5..2545365efe2e 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestTypeEnum.java @@ -5,7 +5,6 @@ * * http://www.dspace.org/license/ */ - package org.dspace.app.rest.model; /** @@ -28,4 +27,23 @@ public enum HarvestTypeEnum { public int getValue() { return harvestType; } + + /** + * Creates an enum from the given integer + * @param harvestType The harvest type + * @return a harvestTypeEnum + */ + public static HarvestTypeEnum fromInt(Integer harvestType) { + if (harvestType == null) { + return HarvestTypeEnum.NONE; + } + + switch (harvestType) { + case 0: return HarvestTypeEnum.NONE; + case 1: return HarvestTypeEnum.METADATA_ONLY; + case 2: return HarvestTypeEnum.METADATA_AND_REF; + case 3: return HarvestTypeEnum.METADATA_AND_BITSTREAMS; + default: throw new IllegalArgumentException("No corresponding enum value for integer"); + } + } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java index ca2c142d4eef..2f6282ab6368 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java @@ -7,8 +7,11 @@ */ package org.dspace.app.rest.model; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import org.dspace.app.rest.CollectionHarvestSettingsController; /** * The HarvestCollection REST Resource @@ -17,7 +20,7 @@ */ public class HarvestedCollectionRest extends BaseObjectRest { - public static final String NAME = "harvestedCollection"; + public static final String NAME = "collections"; public static final String CATEGORY = "core"; @JsonProperty("harvest_type") @@ -29,25 +32,63 @@ public class HarvestedCollectionRest extends BaseObjectRest { @JsonProperty("oai_set_id") private String oaiSetId; + @JsonProperty("harvest_message") + private String harvestMessage; + @JsonProperty("metadata_config_id") private String metadataConfigId; + @JsonProperty("harvest_status") + private HarvestStatusEnum harvestStatus; + + @JsonProperty("harvest_start_time") + private Date harvestStartTime; + + @JsonProperty("last_harvested") + private Date lastHarvested; + + private HarvesterMetadataRest metadata_configs; + + private CollectionRest collectionRest; + + @JsonIgnore + @Override + public Integer getId() { + return id; + } + public String getCategory() { return CATEGORY; } public Class getController() { - return CollectionHarvestSettingsController.class; + return HarvestedCollectionRest.class; } + @JsonIgnore public String getType() { return NAME; } + @JsonIgnore + public CollectionRest getCollectionRest() { + return this.collectionRest; + } + + public void setCollection(CollectionRest collectionRest) { + this.collectionRest = collectionRest; + } + + @JsonIgnore public int getHarvestType() { return harvestType.ordinal(); } + @JsonGetter("harvest_type") + public String getHarvestTypeAsString() { + return harvestType.name(); + } + public void setHarvestType(HarvestTypeEnum harvestType) { this.harvestType = harvestType; } @@ -75,4 +116,55 @@ public String getMetadataConfigId() { public void setMetadataConfigId(String metadataConfigId) { this.metadataConfigId = metadataConfigId; } + + + public String getHarvestMessage() { + return harvestMessage; + } + + public void setHarvestMessage(String harvestMessage) { + this.harvestMessage = harvestMessage; + } + + @JsonIgnore + public HarvestStatusEnum getHarvestStatus() { + return harvestStatus; + } + + @JsonGetter("harvest_status") + public String getHarvestStatusAsString() { + return harvestStatus == null ? null : harvestStatus.name(); + } + + public void setHarvestStatus(HarvestStatusEnum harvestStatus) { + this.harvestStatus = harvestStatus; + } + + public Date getHarvestStartTime() { + return harvestStartTime; + } + + public void setHarvestStartTime(Date harvestStartTime) { + this.harvestStartTime = harvestStartTime; + } + + public Date getLastHarvested() { + return lastHarvested; + } + + public void setLastHarvested(Date lastHarvested) { + this.lastHarvested = lastHarvested; + } + + @LinkRest(linkClass = HarvesterMetadataRest.class, name = "metadata_configs", optional = true) + @JsonIgnore + public HarvesterMetadataRest getMetadataConfigs() { + return metadata_configs; + } + + public void setMetadataConfigs(HarvesterMetadataRest metadata_configs) { + this.metadata_configs = metadata_configs; + } + + } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java index a160a221b639..a32e901d74c5 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvesterMetadataRest.java @@ -7,6 +7,7 @@ */ package org.dspace.app.rest.model; +import java.io.Serializable; import java.util.List; import java.util.Map; @@ -18,16 +19,16 @@ * * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ -public class HarvesterMetadataRest extends BaseObjectRest { +public class HarvesterMetadataRest extends BaseObjectRest { - public static final String NAME = "harvestermetadata"; - public static final String CATEGORY = RestAddressableModel.CONFIGURATION; + public static final String CATEGORY = "config"; + public static final String NAME = "harvesterMetadata"; private List> configs; @Override @JsonIgnore - public String getId() { + public Serializable getId() { return id; } @@ -36,15 +37,16 @@ public String getCategory() { return CATEGORY; } - public Class getController() { - return HarvesterMetadataController.class; - } - @JsonIgnore public String getType() { return NAME; } + + public Class getController() { + return HarvesterMetadataController.class; + } + public List> getConfigs() { return configs; } @@ -53,6 +55,4 @@ public void setConfigs(List> configs) { this.configs = configs; } - - } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java new file mode 100644 index 000000000000..15140d53ab67 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java @@ -0,0 +1,37 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.model.hateoas; + +import org.dspace.app.rest.model.HarvestedCollectionRest; +import org.dspace.app.rest.model.HarvesterMetadataRest; +import org.dspace.app.rest.utils.Utils; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * HarvestedCollection Rest HAL Resource. The HAL Resource wraps the REST Resource + * adding support for the links and embedded resources + * + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) + */ +public class HarvestedCollectionResource extends HALResource { + + @Autowired + private Utils utils; + + public HarvestedCollectionResource(HarvestedCollectionRest data) { + super(data); + embedResource("metadata_configs", data.getMetadataConfigs()); + } + + private void embedResource(String relationship, HarvesterMetadataRest harvesterMetadataRest) { + HarvesterMetadataResource harvesterMetadataResource = + new HarvesterMetadataResource(harvesterMetadataRest, utils); + embedResource(relationship, harvesterMetadataResource); + } + +} \ No newline at end of file diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java index ec08e398fd17..f7226d8956f4 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvesterMetadataResource.java @@ -11,8 +11,8 @@ import org.dspace.app.rest.utils.Utils; /** - * Harvester metadata rest HAL Resource. The HAL Resource wraps the REST Resource - * adding support for the links. + * HarvesterMetadata Rest HAL Resource. The HAL Resource wraps the REST Resource + * adding support for the links and embedded resources * * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) */ @@ -22,4 +22,4 @@ public HarvesterMetadataResource(HarvesterMetadataRest data, Utils utils, String super(data, utils, rels); } -} +} \ No newline at end of file diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java new file mode 100644 index 000000000000..ee3b64e7ec5a --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java @@ -0,0 +1,50 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +import org.dspace.app.rest.converter.HarvestedCollectionConverter; +import org.dspace.app.rest.model.HarvestedCollectionRest; +import org.dspace.content.Collection; +import org.dspace.core.Context; +import org.dspace.harvest.HarvestedCollection; +import org.dspace.harvest.OAIHarvester; +import org.dspace.harvest.service.HarvestedCollectionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * This is the repository responsible for managing the HarvestedCollection Rest object + * + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) + */ +@Component(HarvestedCollectionRest.CATEGORY + "." + HarvestedCollectionRest.NAME) +public class HarvestedCollectionRestRepository extends AbstractDSpaceRestRepository { + + @Autowired + HarvestedCollectionService harvestedCollectionService; + + @Autowired + HarvestedCollectionConverter harvestedCollectionConverter; + + public HarvestedCollectionRest findOne(Collection collection) throws SQLException { + Context context = obtainContext(); + + if (collection == null) { + return null; + } + + HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); + List> configs = OAIHarvester.getAvailableMetadataFormats(); + return harvestedCollectionConverter.fromModel(harvestedCollection, collection, configs); + } + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java new file mode 100644 index 000000000000..adb8f9b1a8e7 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java @@ -0,0 +1,42 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.repository; + +import org.dspace.app.rest.model.HarvesterMetadataRest; +import org.dspace.app.rest.model.hateoas.HarvesterMetadataResource; +import org.dspace.core.Context; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +/** + * This is the repository responsible for managing the HarvesterMetadata Rest object + * + * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) + */ +@Component(HarvesterMetadataRest.CATEGORY + "." + HarvesterMetadataRest.NAME) +public class HarvesterMetadataRestRepository extends DSpaceRestRepository { + + public HarvesterMetadataRest findOne(Context context, String s) { + return null; + } + + public Page findAll(Context context, Pageable pageable) { + return null; + } + + public Class getDomainClass() { + return null; + } + + public HarvesterMetadataResource wrapResource(HarvesterMetadataRest item, String... rels) { + return new HarvesterMetadataResource(item, utils, rels); + } + + +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index 68dfb0564952..c042cae7563e 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -7,19 +7,30 @@ */ package org.dspace.app.rest; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.List; +import java.util.Map; + import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.matcher.MetadataConfigsMatcher; import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.harvest.HarvestedCollection; +import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.service.HarvestedCollectionService; +import org.hamcrest.Matchers; import org.json.JSONObject; import org.junit.Before; import org.junit.Test; @@ -33,6 +44,7 @@ public class CollectionHarvestSettingsControllerIT extends AbstractControllerIntegrationTest { Collection collection; + Collection collectionNoHarvestSettings; @Autowired HarvestedCollectionService harvestedCollectionService; @@ -48,6 +60,9 @@ public void SetUp() { .withName("Sub Community") .build(); collection = CollectionBuilder.createCollection(context, community).withName("Collection 1").build(); + collectionNoHarvestSettings = CollectionBuilder.createCollection(context, community) + .withName("Collection 2") + .build(); context.restoreAuthSystemState(); } @@ -71,7 +86,79 @@ public JSONObject createHarvestSettingsJson(String harvestType, } @Test - public void EndpointWorksWithStandardSettings() throws Exception { + public void GetCollectionHarvestSettings() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + List> configs = OAIHarvester.getAvailableMetadataFormats(); + + // Add harvest settings to collection + JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.org/oai/request", "col_1721.1_114174", "dc"); + + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json") + .content(json.toString())) + .andExpect(status().isOk()); + + //Retrieve harvest settings + getClient(token).perform( + get("/api/core/collections/" + collection.getID() + "/harvester")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.harvest_type", is("METADATA_ONLY"))) + .andExpect(jsonPath("$.oai_source", is("https://dspace.org/oai/request"))) + .andExpect(jsonPath("$.oai_set_id", is("col_1721.1_114174"))) + .andExpect(jsonPath("$.harvest_message", is(nullValue()))) + .andExpect(jsonPath("$.metadata_config_id", is("dc"))) + .andExpect(jsonPath("$.harvest_status", is("READY"))) + .andExpect(jsonPath("$.harvest_start_time", is(nullValue()))) + .andExpect(jsonPath("$.last_harvested", is(nullValue()))) + .andExpect(jsonPath("$._links.self.href", + endsWith("api/core/collections/" + collection.getID() + "/harvester"))) + .andExpect(jsonPath("$._embedded.metadata_configs", Matchers.allOf( + MetadataConfigsMatcher.matchMetadataConfigs(configs) + ))) + .andExpect(jsonPath("$._embedded.metadata_configs._links.self.href", + endsWith("/api/config/harvestermetadata"))); + } + + @Test + public void GetCollectionHarvestSettingsIfNotAdmin() throws Exception { + String token = getAuthToken(eperson.getEmail(), password); + + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json")) + .andExpect(status().isForbidden()); + } + + @Test + public void getCollectionHarvestSettingsIfNotSet() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + List> configs = OAIHarvester.getAvailableMetadataFormats(); + + getClient(token).perform( + get("/api/core/collections/" + collectionNoHarvestSettings.getID() + "/harvester")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.harvest_type", is("NONE"))) + .andExpect(jsonPath("$.oai_source", is(nullValue()))) + .andExpect(jsonPath("$.oai_set_id", is(nullValue()))) + .andExpect(jsonPath("$.harvest_message", is(nullValue()))) + .andExpect(jsonPath("$.metadata_config_id", is(nullValue()))) + .andExpect(jsonPath("$.harvest_status", is(nullValue()))) + .andExpect(jsonPath("$.harvest_start_time", is(nullValue()))) + .andExpect(jsonPath("$.last_harvested", is(nullValue()))) + .andExpect(jsonPath("$._links.self.href", + endsWith("api/core/collections/" + collectionNoHarvestSettings.getID() + "/harvester"))) + .andExpect(jsonPath("$._embedded.metadata_configs", Matchers.allOf( + MetadataConfigsMatcher.matchMetadataConfigs(configs) + ))) + .andExpect(jsonPath("$._embedded.metadata_configs._links.self.href", + endsWith("/api/config/harvestermetadata"))); + } + + @Test + public void PutWorksWithStandardSettings() throws Exception { String token = getAuthToken(admin.getEmail(), password); JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.org/oai/request", "col_1721.1_114174", "dc"); @@ -92,7 +179,7 @@ public void EndpointWorksWithStandardSettings() throws Exception { } @Test - public void UnProcessableEntityIfIncorrectSettings() throws Exception { + public void PutUnProcessableEntityIfIncorrectSettings() throws Exception { String token = getAuthToken(admin.getEmail(), password); JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.mit.edu/iao/request", "col_1721.1_114174", "bc"); @@ -105,7 +192,7 @@ public void UnProcessableEntityIfIncorrectSettings() throws Exception { } @Test - public void HarvestSettingsDeletedIfHarvestTypeIsNone() throws Exception { + public void PutHarvestSettingsDeletedIfHarvestTypeIsNone() throws Exception { String token = getAuthToken(admin.getEmail(), password); JSONObject json = createHarvestSettingsJson("NONE", "", "", "dc"); @@ -122,14 +209,14 @@ public void HarvestSettingsDeletedIfHarvestTypeIsNone() throws Exception { } @Test - public void UnauthorizedIfNotAuthenticated() throws Exception { + public void PutUnauthorizedIfNotAuthenticated() throws Exception { getClient().perform(put("/api/core/collections/" + collection.getID() + "/harvester") .contentType("application/json")) .andExpect(status().isUnauthorized()); } @Test - public void ForbiddenIfNotEnoughpermissions() throws Exception { + public void PutForbiddenIfNotEnoughpermissions() throws Exception { String token = getAuthToken(eperson.getEmail(), password); getClient(token).perform(put("/api/core/collections/" + collection.getID() + "/harvester") @@ -138,7 +225,7 @@ public void ForbiddenIfNotEnoughpermissions() throws Exception { } @Test - public void NotFoundIfNoSuchCollection() throws Exception { + public void PutNotFoundIfNoSuchCollection() throws Exception { String token = getAuthToken(admin.getEmail(), password); String fakeUuid = "6c9a081e-f2e5-42cd-8cf8-338f64b0841b"; @@ -148,7 +235,7 @@ public void NotFoundIfNoSuchCollection() throws Exception { } @Test - public void UnprocessableEntityIfHarvestTypeIncorrect() throws Exception { + public void PutUnprocessableEntityIfHarvestTypeIncorrect() throws Exception { String token = getAuthToken(admin.getEmail(), password); JSONObject json = createHarvestSettingsJson("INCORRECT_HARVEST_TYPE", "https://dspace.mit.edu/oai/request", "col_1721.1_114174", "dc"); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java index e1e235c22a06..8bc2fac5e607 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java @@ -1,18 +1,24 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ package org.dspace.app.rest; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.endsWith; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.List; import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; +import org.dspace.app.rest.matcher.MetadataConfigsMatcher; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; import org.dspace.harvest.OAIHarvester; +import org.hamcrest.Matchers; import org.junit.Test; /** @@ -28,15 +34,12 @@ public void GetReturnsAllAvailableMetadataFormats() throws Exception { List> configs = OAIHarvester.getAvailableMetadataFormats(); - Function> getAllValues = - key -> configs.stream().map(x -> x.get(key)).collect(Collectors.toList()); - getClient(token).perform( get("/api/config/harvestermetadata")) .andExpect(status().isOk()) - .andExpect(jsonPath("$.configs[*].id", is(getAllValues.apply("id")))) - .andExpect(jsonPath("$.configs[*].label", is(getAllValues.apply("label")))) - .andExpect(jsonPath("$.configs[*].namespace", is(getAllValues.apply("namespace")))) - .andExpect(jsonPath("$._links.self.href", notNullValue())); + .andExpect(jsonPath("$", Matchers.allOf( + MetadataConfigsMatcher.matchMetadataConfigs(configs) + ))) + .andExpect(jsonPath("$._links.self.href", endsWith("/api/config/harvestermetadata"))); } } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/MetadataConfigsMatcher.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/MetadataConfigsMatcher.java new file mode 100644 index 000000000000..a8aa99c35dc1 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/matcher/MetadataConfigsMatcher.java @@ -0,0 +1,48 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.is; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.hamcrest.Matcher; + +/** + * Class used for matching metadata configurations in JSON + */ +public class MetadataConfigsMatcher { + + private MetadataConfigsMatcher() { } + + public static Matcher matchMetadataConfigs(List> configs) { + + /** + * This function returns a list of values, containing the values matching the key for each + * configuration (Map) in the list. For example, getAllValues("id") returns + * a list with the ids of every configuration in the list. + */ + Function> getAllValues = key -> configs.stream() + .map(x -> x.get(key)) + .collect(Collectors.toList()); + + return allOf( + hasJsonPath("$.configs[*].id", is(getAllValues.apply("id"))), + hasJsonPath("$.configs[*].label", is(getAllValues.apply("label"))), + hasJsonPath("$.configs[*].namespace", is(getAllValues.apply("namespace"))), + hasJsonPath("$._links.self.href", endsWith("/api/config/harvestermetadata")) + ); + } + +} From 1831c4f92d04d1ac7e7062bb28155dc23fdace67 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Tue, 13 Aug 2019 13:06:51 +0200 Subject: [PATCH 13/23] Fix small issues --- .../CollectionHarvestSettingsController.java | 5 +- .../config/spring/api/core-services-mock.xml | 9 ++ .../config/spring/api/core-services.xml | 116 ------------------ 3 files changed, 11 insertions(+), 119 deletions(-) create mode 100644 dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml delete mode 100644 dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index ae103213e10d..a10db566d3cf 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -135,7 +135,7 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, harvestedCollectionService.delete(context, harvestedCollection); } else if (harvestedCollectionRest.getHarvestType() != HarvestTypeEnum.NONE.getValue()) { - List errors = testHarvestSettings(collection, harvestedCollectionRest); + List errors = testHarvestSettings(harvestedCollectionRest); if (errors.size() == 0) { if (harvestedCollection == null) { @@ -159,8 +159,7 @@ public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, * @param harvestedCollectionRest A object containg the harvest settings to be tested * @return */ - private List testHarvestSettings(Collection collection, - HarvestedCollectionRest harvestedCollectionRest) { + private List testHarvestSettings(HarvestedCollectionRest harvestedCollectionRest) { int harvestType = harvestedCollectionRest.getHarvestType(); String metadataConfigId = harvestedCollectionRest.getMetadataConfigId(); diff --git a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml new file mode 100644 index 000000000000..4412283f4793 --- /dev/null +++ b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml deleted file mode 100644 index b58f7db043d7..000000000000 --- a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - news-top.html - news-side.html - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 0f4ea918344d38b861681a9a41fed3b66b5cb6aa Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Wed, 21 Aug 2019 10:35:23 +0200 Subject: [PATCH 14/23] Clean up code added in previous commits --- .../CollectionHarvestSettingsController.java | 122 +++------------- .../HarvestedCollectionRestRepository.java | 137 ++++++++++++++++++ .../HarvesterMetadataRestRepository.java | 42 ------ .../config/spring/api/core-services-mock.xml | 2 +- ...CollectionHarvestSettingsControllerIT.java | 42 +++++- 5 files changed, 193 insertions(+), 152 deletions(-) delete mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index a10db566d3cf..beb8d8536171 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -7,21 +7,15 @@ */ package org.dspace.app.rest; -import java.io.IOException; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; -import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.dspace.app.rest.exception.UnprocessableEntityException; +import org.dspace.app.rest.converter.HarvestedCollectionConverter; import org.dspace.app.rest.link.HalLinkService; -import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.app.rest.model.HarvestedCollectionRest; import org.dspace.app.rest.model.hateoas.HarvestedCollectionResource; import org.dspace.app.rest.repository.HarvestedCollectionRestRepository; @@ -52,6 +46,9 @@ "}}/harvester") public class CollectionHarvestSettingsController { + @Autowired + HarvestedCollectionConverter harvestedCollectionConverter; + @Autowired CollectionService collectionService; @@ -94,7 +91,6 @@ public HarvestedCollectionResource get(@PathVariable UUID collectionUuid, return resource; } - /** * PUT Endpoint for updating the settings of a collection. * @@ -103,117 +99,33 @@ public HarvestedCollectionResource get(@PathVariable UUID collectionUuid, * @param request The request object * @throws SQLException */ + @PreAuthorize("hasPermission(#collectionUuid, 'COLLECTION', 'WRITE')") @RequestMapping(method = RequestMethod.PUT, consumes = {"application/json"}) - @PreAuthorize("hasAuthority('ADMIN')") - public void updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, + public HarvestedCollectionResource updateHarvestSettingsEndpoint(@PathVariable UUID collectionUuid, HttpServletResponse response, HttpServletRequest request) throws SQLException { Context context = ContextUtil.obtainContext(request); Collection collection = collectionService.find(context, collectionUuid); + HarvestedCollectionResource harvestedCollectionResource = null; if (collection == null) { throw new ResourceNotFoundException("Collection with uuid: " + collectionUuid + " not found"); } - // Parse json into HarvestCollectionRest - ObjectMapper mapper = new ObjectMapper(); - HarvestedCollectionRest harvestedCollectionRest; - - try { - ServletInputStream input = request.getInputStream(); - harvestedCollectionRest = mapper.readValue(input, HarvestedCollectionRest.class); - } catch (IOException e) { - throw new UnprocessableEntityException("Error parsing request body: " + e.toString(), e); - } - - HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); - - // Delete harvestedCollectionService object if harvest type is not set - if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue() - && harvestedCollection != null) { - harvestedCollectionService.delete(context, harvestedCollection); - - } else if (harvestedCollectionRest.getHarvestType() != HarvestTypeEnum.NONE.getValue()) { - List errors = testHarvestSettings(harvestedCollectionRest); - - if (errors.size() == 0) { - if (harvestedCollection == null) { - harvestedCollection = harvestedCollectionService.create(context, collection); - } - - updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); - } else { - throw new UnprocessableEntityException( - "Incorrect harvest settings in request. The following errors were found: " + errors.toString() - ); - } - } - - context.complete(); - } + HarvestedCollection harvestedCollection = + harvestedCollectionRestRepository.update(context, request, collection); - /** - * Function used to verify that the harvest settings work - * @param collection The collection to which the harvest settings should be aplied - * @param harvestedCollectionRest A object containg the harvest settings to be tested - * @return - */ - private List testHarvestSettings(HarvestedCollectionRest harvestedCollectionRest) { - - int harvestType = harvestedCollectionRest.getHarvestType(); - String metadataConfigId = harvestedCollectionRest.getMetadataConfigId(); - - List errors = new ArrayList<>(); - - // See if metadata config identifier appears in available metadata formats - List> metadataFormats = OAIHarvester.getAvailableMetadataFormats(); - boolean inAvailableMetadataFormats = metadataFormats.stream() - .filter(x -> x.get("id").equals(metadataConfigId)) - .count() >= 1; - - if (inAvailableMetadataFormats) { - boolean testORE = Arrays.asList( - HarvestTypeEnum.METADATA_AND_REF.getValue(), - HarvestTypeEnum.METADATA_AND_BITSTREAMS.getValue() - ).contains(harvestType); - - // Actually verify the harvest settings - List verificationErrors = harvestedCollectionService.verifyOAIharvester( - harvestedCollectionRest.getOaiSource(), - harvestedCollectionRest.getOaiSetId(), - metadataConfigId, - testORE - ); - errors = verificationErrors; - } else { - errors.add( - "The metadata format with identifier '" + metadataConfigId + "' is not an available metadata format." - ); + // Return a harvestedCollectionResource only if a new harvestedCollection was created + if (harvestedCollection != null) { + List> configs = OAIHarvester.getAvailableMetadataFormats(); + HarvestedCollectionRest harvestedCollectionRest = + harvestedCollectionConverter.fromModel(harvestedCollection, collection, configs); + harvestedCollectionResource = new HarvestedCollectionResource(harvestedCollectionRest); } - return errors; - } + context.commit(); - /** - * Function to update the harvest settings of a collection - * @param context The context object - * @param harvestedCollection The harvestedCollection whose settings should be updated - * @param harvestedCollectionRest An object containing the new harvest settings - * @throws SQLException - */ - private void updateCollectionHarvestSettings(Context context, HarvestedCollection harvestedCollection, - HarvestedCollectionRest harvestedCollectionRest) throws SQLException { - int harvestType = harvestedCollectionRest.getHarvestType(); - String oaiSource = harvestedCollectionRest.getOaiSource(); - String oaiSetId = harvestedCollectionRest.getOaiSetId(); - String metadataConfigId = harvestedCollectionRest.getMetadataConfigId(); - - harvestedCollection.setHarvestType(harvestType); - harvestedCollection.setOaiSource(oaiSource); - harvestedCollection.setOaiSetId(oaiSetId); - harvestedCollection.setHarvestMetadataConfig(metadataConfigId); - - harvestedCollectionService.update(context, harvestedCollection); + return harvestedCollectionResource; } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java index ee3b64e7ec5a..5ff68064d9e9 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java @@ -7,11 +7,20 @@ */ package org.dspace.app.rest.repository; +import java.io.IOException; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; + +import com.fasterxml.jackson.databind.ObjectMapper; import org.dspace.app.rest.converter.HarvestedCollectionConverter; +import org.dspace.app.rest.exception.UnprocessableEntityException; +import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.app.rest.model.HarvestedCollectionRest; import org.dspace.content.Collection; import org.dspace.core.Context; @@ -21,6 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; + /** * This is the repository responsible for managing the HarvestedCollection Rest object * @@ -47,4 +57,131 @@ public HarvestedCollectionRest findOne(Collection collection) throws SQLExceptio return harvestedCollectionConverter.fromModel(harvestedCollection, collection, configs); } + /** + * Function to update the harvesting settings of a collection + * @param context The context object + * @param request The incoming put request + * @param collection The collection whose settings should be changed + * @return a harvestedCollection if a new harvestedCollection is created, otherwise null + * @throws SQLException + */ + public HarvestedCollection update(Context context, + HttpServletRequest request, + Collection collection) throws SQLException { + HarvestedCollectionRest harvestedCollectionRest = parseHarvestedCollectionRest(context, request, collection); + HarvestedCollection harvestedCollection = harvestedCollectionService.find(context, collection); + + // Delete harvestedCollectionService object if harvest type is not set + if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue() + && harvestedCollection != null) { + harvestedCollectionService.delete(context, harvestedCollection); + + } else if (harvestedCollectionRest.getHarvestType() != HarvestTypeEnum.NONE.getValue()) { + List errors = testHarvestSettings(harvestedCollectionRest); + + if (errors.size() == 0) { + if (harvestedCollection == null) { + harvestedCollection = harvestedCollectionService.create(context, collection); + } + + updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); + harvestedCollection = harvestedCollectionService.find(context, collection); + return harvestedCollection; + } else { + throw new UnprocessableEntityException( + "Incorrect harvest settings in request. The following errors were found: " + errors.toString() + ); + } + } + return null; + } + + /** + * Function to parse a harvestedCollectionRest from an incoming put request + * @param context The context object + * @param request The incoming put request + * @param collection The collection to which the harvestedCollection belongs + * @return The harvestedCollectionRest object contained inn the request + */ + private HarvestedCollectionRest parseHarvestedCollectionRest(Context context, + HttpServletRequest request, + Collection collection) throws SQLException { + ObjectMapper mapper = new ObjectMapper(); + HarvestedCollectionRest harvestedCollectionRest; + + try { + ServletInputStream input = request.getInputStream(); + harvestedCollectionRest = mapper.readValue(input, HarvestedCollectionRest.class); + } catch (IOException e) { + throw new UnprocessableEntityException("Error parsing request body: " + e.toString(), e); + } + + return harvestedCollectionRest; + } + + /** + * Function to update the harvest settings of a collection + * @param context The context object + * @param harvestedCollection The harvestedCollection whose settings should be updated + * @param harvestedCollectionRest An object containing the new harvest settings + * @throws SQLException + */ + private void updateCollectionHarvestSettings(Context context, HarvestedCollection harvestedCollection, + HarvestedCollectionRest harvestedCollectionRest) throws SQLException { + int harvestType = harvestedCollectionRest.getHarvestType(); + String oaiSource = harvestedCollectionRest.getOaiSource(); + String oaiSetId = harvestedCollectionRest.getOaiSetId(); + String metadataConfigId = harvestedCollectionRest.getMetadataConfigId(); + + harvestedCollection.setHarvestType(harvestType); + harvestedCollection.setOaiSource(oaiSource); + harvestedCollection.setOaiSetId(oaiSetId); + harvestedCollection.setHarvestMetadataConfig(metadataConfigId); + + harvestedCollectionService.update(context, harvestedCollection); + } + + + /** + * Function used to verify that the harvest settings work + * @param collection The collection to which the harvest settings should be aplied + * @param harvestedCollectionRest A object containg the harvest settings to be tested + * @return + */ + private List testHarvestSettings(HarvestedCollectionRest harvestedCollectionRest) { + + int harvestType = harvestedCollectionRest.getHarvestType(); + String metadataConfigId = harvestedCollectionRest.getMetadataConfigId(); + + List errors = new ArrayList<>(); + + // See if metadata config identifier appears in available metadata formats + List> metadataFormats = OAIHarvester.getAvailableMetadataFormats(); + boolean inAvailableMetadataFormats = metadataFormats.stream() + .filter(x -> x.get("id").equals(metadataConfigId)) + .count() >= 1; + + if (inAvailableMetadataFormats) { + boolean testORE = Arrays.asList( + HarvestTypeEnum.METADATA_AND_REF.getValue(), + HarvestTypeEnum.METADATA_AND_BITSTREAMS.getValue() + ).contains(harvestType); + + // Actually verify the harvest settings + List verificationErrors = harvestedCollectionService.verifyOAIharvester( + harvestedCollectionRest.getOaiSource(), + harvestedCollectionRest.getOaiSetId(), + metadataConfigId, + testORE + ); + errors = verificationErrors; + } else { + errors.add( + "The metadata format with identifier '" + metadataConfigId + "' is not an available metadata format." + ); + } + + return errors; + } + } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java deleted file mode 100644 index adb8f9b1a8e7..000000000000 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvesterMetadataRestRepository.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.app.rest.repository; - -import org.dspace.app.rest.model.HarvesterMetadataRest; -import org.dspace.app.rest.model.hateoas.HarvesterMetadataResource; -import org.dspace.core.Context; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Component; - -/** - * This is the repository responsible for managing the HarvesterMetadata Rest object - * - * @author Jelle Pelgrims (jelle.pelgrims at atmire.com) - */ -@Component(HarvesterMetadataRest.CATEGORY + "." + HarvesterMetadataRest.NAME) -public class HarvesterMetadataRestRepository extends DSpaceRestRepository { - - public HarvesterMetadataRest findOne(Context context, String s) { - return null; - } - - public Page findAll(Context context, Pageable pageable) { - return null; - } - - public Class getDomainClass() { - return null; - } - - public HarvesterMetadataResource wrapResource(HarvesterMetadataRest item, String... rels) { - return new HarvesterMetadataResource(item, utils, rels); - } - - -} diff --git a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml index 4412283f4793..ff13e7f6b48a 100644 --- a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml +++ b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/core-services-mock.xml @@ -5,5 +5,5 @@ default-lazy-init="true"> - + diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index c042cae7563e..4dc5e06c9efa 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -17,16 +17,22 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.sql.SQLException; import java.util.List; import java.util.Map; import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.EPersonBuilder; import org.dspace.app.rest.matcher.MetadataConfigsMatcher; import org.dspace.app.rest.model.HarvestTypeEnum; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Collection; import org.dspace.content.Community; +import org.dspace.core.Constants; +import org.dspace.eperson.EPerson; import org.dspace.harvest.HarvestedCollection; import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.service.HarvestedCollectionService; @@ -43,14 +49,18 @@ */ public class CollectionHarvestSettingsControllerIT extends AbstractControllerIntegrationTest { - Collection collection; - Collection collectionNoHarvestSettings; + @Autowired + AuthorizeService authorizeService; @Autowired HarvestedCollectionService harvestedCollectionService; + Collection collection; + Collection collectionNoHarvestSettings; + EPerson ePersonWithWriteRights; + @Before - public void SetUp() { + public void SetUp() throws SQLException, AuthorizeException { context.turnOffAuthorisationSystem(); parentCommunity = CommunityBuilder.createCommunity(context) @@ -59,11 +69,22 @@ public void SetUp() { Community community = CommunityBuilder.createSubCommunity(context, parentCommunity) .withName("Sub Community") .build(); - collection = CollectionBuilder.createCollection(context, community).withName("Collection 1").build(); + + collection = CollectionBuilder.createCollection(context, community) + .withName("Collection 1") + .build(); + collectionNoHarvestSettings = CollectionBuilder.createCollection(context, community) .withName("Collection 2") .build(); + ePersonWithWriteRights = EPersonBuilder.createEPerson(context) + .withEmail("email@email.com") + .withPassword(password) + .build(); + + authorizeService.addPolicy(context, collection, Constants.WRITE, ePersonWithWriteRights); + context.restoreAuthSystemState(); } @@ -131,6 +152,19 @@ public void GetCollectionHarvestSettingsIfNotAdmin() throws Exception { .andExpect(status().isForbidden()); } + @Test + public void GetCollectionHarvestSettingsIfUserHasWriteRights() throws Exception { + context.setCurrentUser(ePersonWithWriteRights); + String token = getAuthToken(ePersonWithWriteRights.getEmail(), password); + JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.org/oai/request", "col_1721.1_114174", "dc"); + + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json") + .content(json.toString())) + .andExpect(status().isOk()); + } + @Test public void getCollectionHarvestSettingsIfNotSet() throws Exception { String token = getAuthToken(admin.getEmail(), password); From f5561a2dfc7e7ee5a7d16929a39274963176f569 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Wed, 21 Aug 2019 11:11:16 +0200 Subject: [PATCH 15/23] Add small changes --- .../app/rest/CollectionHarvestSettingsController.java | 3 ++- .../app/rest/CollectionHarvestSettingsControllerIT.java | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index beb8d8536171..3708fa95d63a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -70,7 +70,7 @@ public class CollectionHarvestSettingsController { * @param response The response object * @return a HarvesterMetadataResource containing all available metadata formats */ - @PreAuthorize("hasAuthority('ADMIN')") + @PreAuthorize("hasPermission(#collectionUuid, 'COLLECTION', 'READ')") @RequestMapping(method = RequestMethod.GET) public HarvestedCollectionResource get(@PathVariable UUID collectionUuid, HttpServletRequest request, @@ -122,6 +122,7 @@ public HarvestedCollectionResource updateHarvestSettingsEndpoint(@PathVariable U HarvestedCollectionRest harvestedCollectionRest = harvestedCollectionConverter.fromModel(harvestedCollection, collection, configs); harvestedCollectionResource = new HarvestedCollectionResource(harvestedCollectionRest); + halLinkService.addLinks(harvestedCollectionResource); } context.commit(); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index 4dc5e06c9efa..a3e448edef01 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -153,7 +153,7 @@ public void GetCollectionHarvestSettingsIfNotAdmin() throws Exception { } @Test - public void GetCollectionHarvestSettingsIfUserHasWriteRights() throws Exception { + public void GetAndPutCollectionHarvestSettingsIfUserHasWriteRights() throws Exception { context.setCurrentUser(ePersonWithWriteRights); String token = getAuthToken(ePersonWithWriteRights.getEmail(), password); JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.org/oai/request", "col_1721.1_114174", "dc"); @@ -163,6 +163,11 @@ public void GetCollectionHarvestSettingsIfUserHasWriteRights() throws Exception .contentType("application/json") .content(json.toString())) .andExpect(status().isOk()); + + getClient(token).perform( + get("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json")) + .andExpect(status().isOk()); } @Test From 8c60fbb3e2f9962e6eba04072e3e04e4c1aa8508 Mon Sep 17 00:00:00 2001 From: Jelle Pelgrims Date: Wed, 21 Aug 2019 11:19:21 +0200 Subject: [PATCH 16/23] Fix CollectionharvestSettingsController permissions --- .../dspace/app/rest/CollectionHarvestSettingsController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 3708fa95d63a..dc6ec531e546 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -70,7 +70,7 @@ public class CollectionHarvestSettingsController { * @param response The response object * @return a HarvesterMetadataResource containing all available metadata formats */ - @PreAuthorize("hasPermission(#collectionUuid, 'COLLECTION', 'READ')") + @PreAuthorize("hasPermission(#collectionUuid, 'COLLECTION', 'WRITE')") @RequestMapping(method = RequestMethod.GET) public HarvestedCollectionResource get(@PathVariable UUID collectionUuid, HttpServletRequest request, From 2c025684758dd533b53d38ea43b7ad46f0fee073 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 3 Sep 2019 11:50:00 +0200 Subject: [PATCH 17/23] Added the harvester link to the CollectionResource --- .../src/main/java/org/dspace/app/rest/model/CollectionRest.java | 1 + .../org/dspace/app/rest/model/hateoas/CollectionResource.java | 1 + 2 files changed, 2 insertions(+) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CollectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CollectionRest.java index 77bb99200432..eca097952db2 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CollectionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CollectionRest.java @@ -25,6 +25,7 @@ public class CollectionRest extends DSpaceObjectRest { public static final String NAME = "collection"; public static final String CATEGORY = RestAddressableModel.CORE; public static final String LICENSE = "license"; + public static final String HARVEST = "harvester"; public static final String DEFAULT_ACCESS_CONDITIONS = "defaultAccessConditions"; @JsonIgnore private BitstreamRest logo; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CollectionResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CollectionResource.java index d955150f7e76..1c08cf2e219c 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CollectionResource.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CollectionResource.java @@ -22,5 +22,6 @@ public class CollectionResource extends DSpaceResource { public CollectionResource(CollectionRest collection, Utils utils, String... rels) { super(collection, utils, rels); add(utils.linkToSubResource(collection, CollectionRest.LICENSE)); + add(utils.linkToSubResource(collection, CollectionRest.HARVEST)); } } From 821e917ace1519352acf556af8130b30076e6362 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 4 Sep 2019 10:04:57 +0200 Subject: [PATCH 18/23] [Task 64789] fixed empty response from update on harvest collections and refactored code --- .../app/rest/CollectionHarvestSettingsController.java | 7 ++----- .../rest/repository/HarvestedCollectionRestRepository.java | 7 +++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index dc6ec531e546..7a7f15811c18 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -113,14 +113,11 @@ public HarvestedCollectionResource updateHarvestSettingsEndpoint(@PathVariable U throw new ResourceNotFoundException("Collection with uuid: " + collectionUuid + " not found"); } - HarvestedCollection harvestedCollection = + HarvestedCollectionRest harvestedCollectionRest = harvestedCollectionRestRepository.update(context, request, collection); // Return a harvestedCollectionResource only if a new harvestedCollection was created - if (harvestedCollection != null) { - List> configs = OAIHarvester.getAvailableMetadataFormats(); - HarvestedCollectionRest harvestedCollectionRest = - harvestedCollectionConverter.fromModel(harvestedCollection, collection, configs); + if (harvestedCollectionRest != null) { harvestedCollectionResource = new HarvestedCollectionResource(harvestedCollectionRest); halLinkService.addLinks(harvestedCollectionResource); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java index 5ff68064d9e9..5cd11df9866a 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/HarvestedCollectionRestRepository.java @@ -65,7 +65,7 @@ public HarvestedCollectionRest findOne(Collection collection) throws SQLExceptio * @return a harvestedCollection if a new harvestedCollection is created, otherwise null * @throws SQLException */ - public HarvestedCollection update(Context context, + public HarvestedCollectionRest update(Context context, HttpServletRequest request, Collection collection) throws SQLException { HarvestedCollectionRest harvestedCollectionRest = parseHarvestedCollectionRest(context, request, collection); @@ -75,6 +75,7 @@ public HarvestedCollection update(Context context, if (harvestedCollectionRest.getHarvestType() == HarvestTypeEnum.NONE.getValue() && harvestedCollection != null) { harvestedCollectionService.delete(context, harvestedCollection); + return harvestedCollectionConverter.fromModel(null); } else if (harvestedCollectionRest.getHarvestType() != HarvestTypeEnum.NONE.getValue()) { List errors = testHarvestSettings(harvestedCollectionRest); @@ -86,7 +87,9 @@ public HarvestedCollection update(Context context, updateCollectionHarvestSettings(context, harvestedCollection, harvestedCollectionRest); harvestedCollection = harvestedCollectionService.find(context, collection); - return harvestedCollection; + List> configs = OAIHarvester.getAvailableMetadataFormats(); + + return harvestedCollectionConverter.fromModel(harvestedCollection, collection, configs); } else { throw new UnprocessableEntityException( "Incorrect harvest settings in request. The following errors were found: " + errors.toString() From 53a4043e03b9a395a34129c1e8aac73674a7989a Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 4 Sep 2019 10:16:51 +0200 Subject: [PATCH 19/23] [Task 64789] added nullcheck for metadata configs --- .../rest/model/hateoas/HarvestedCollectionResource.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java index 15140d53ab67..db8e8c135caa 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java @@ -29,9 +29,11 @@ public HarvestedCollectionResource(HarvestedCollectionRest data) { } private void embedResource(String relationship, HarvesterMetadataRest harvesterMetadataRest) { - HarvesterMetadataResource harvesterMetadataResource = - new HarvesterMetadataResource(harvesterMetadataRest, utils); - embedResource(relationship, harvesterMetadataResource); + if (harvesterMetadataRest != null) { + HarvesterMetadataResource harvesterMetadataResource = + new HarvesterMetadataResource(harvesterMetadataRest, utils); + embedResource(relationship, harvesterMetadataResource); + } } } \ No newline at end of file From 9a026956d762954e8782ab1ce4db222431580f1c Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 17 Sep 2019 13:51:12 +0200 Subject: [PATCH 20/23] Applied feedback --- .../java/org/dspace/harvest/OAIHarvester.java | 3 ++- .../CollectionHarvestSettingsController.java | 4 ---- .../hateoas/HarvestedCollectionResource.java | 2 +- ...CollectionHarvestSettingsControllerIT.java | 19 +++++++++++++++---- .../rest/HarvesterMetadataControllerIT.java | 9 +++++++++ 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index 0202ab5dfa51..96f3da0eaf5b 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -914,7 +914,8 @@ public static List> getAvailableMetadataFormats() { List> configs = new ArrayList<>(); String metaString = "oai.harvester.metadataformats."; Enumeration pe = Collections.enumeration( - DSpaceServicesFactory.getInstance().getConfigurationService().getPropertyKeys("oai") + DSpaceServicesFactory.getInstance().getConfigurationService() + .getPropertyKeys("oai.harvester.metadataformats") ); while (pe.hasMoreElements()) { String key = (String) pe.nextElement(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java index 7a7f15811c18..274c393d9b02 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CollectionHarvestSettingsController.java @@ -8,8 +8,6 @@ package org.dspace.app.rest; import java.sql.SQLException; -import java.util.List; -import java.util.Map; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -24,8 +22,6 @@ import org.dspace.content.Collection; import org.dspace.content.service.CollectionService; import org.dspace.core.Context; -import org.dspace.harvest.HarvestedCollection; -import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.service.HarvestedCollectionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.webmvc.ResourceNotFoundException; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java index db8e8c135caa..56abe66e04ca 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/HarvestedCollectionResource.java @@ -25,7 +25,7 @@ public class HarvestedCollectionResource extends HALResource Date: Fri, 20 Sep 2019 15:25:24 +0200 Subject: [PATCH 21/23] Applied feedback --- .../java/org/dspace/harvest/OAIHarvester.java | 33 +++++++++---------- ...CollectionHarvestSettingsControllerIT.java | 15 ++++++++- .../rest/HarvesterMetadataControllerIT.java | 10 ++++++ 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java index 96f3da0eaf5b..61385095e845 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java +++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java @@ -919,28 +919,25 @@ public static List> getAvailableMetadataFormats() { ); while (pe.hasMoreElements()) { String key = (String) pe.nextElement(); - if (key.startsWith(metaString)) { + String metadataString = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(key); - String metadataString = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty(key); + String id = key.substring(metaString.length()); + String label; + String namespace = ""; - String id = key.substring(metaString.length()); - String label; - String namespace = ""; - - if (metadataString.indexOf(',') != -1) { - label = metadataString.substring(metadataString.indexOf(',') + 2); - namespace = metadataString.substring(0, metadataString.indexOf(',')); - } else { - label = id + "(" + metadataString + ")"; - } + if (metadataString.indexOf(',') != -1) { + label = metadataString.substring(metadataString.indexOf(',') + 2); + namespace = metadataString.substring(0, metadataString.indexOf(',')); + } else { + label = id + "(" + metadataString + ")"; + } - Map config = new HashMap<>(); - config.put("id", id); - config.put("label", label); - config.put("namespace", namespace); + Map config = new HashMap<>(); + config.put("id", id); + config.put("label", label); + config.put("namespace", namespace); - configs.add(config); - } + configs.add(config); } return configs; diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index c67e94d206ba..4751a49613f3 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -171,7 +171,7 @@ public void GetAndPutCollectionHarvestSettingsIfUserHasWriteRights() throws Exce } @Test - public void getAndPutCollectionHarvestSettingsUserNoWriteException() throws Exception { + public void getAndPutCollectionHarvestSettingsAnonymousUserException() throws Exception { JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.org/oai/request", "col_1721.1_114174", "dc"); getClient().perform( @@ -181,6 +181,19 @@ public void getAndPutCollectionHarvestSettingsUserNoWriteException() throws Exce .andExpect(status().isUnauthorized()); } + @Test + public void GetAndPutCollectionHarvestSettingsIfUserHasNoWriteRightsException() throws Exception { + context.setCurrentUser(eperson); + String token = getAuthToken(eperson.getEmail(), password); + JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.org/oai/request", "col_1721.1_114174", "dc"); + + getClient(token).perform( + put("/api/core/collections/" + collection.getID() + "/harvester") + .contentType("application/json") + .content(json.toString())) + .andExpect(status().isForbidden()); + } + @Test public void getCollectionHarvestSettingsIfNotSet() throws Exception { String token = getAuthToken(admin.getEmail(), password); diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java index bd1be00bbe93..f099570cf2a4 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/HarvesterMetadataControllerIT.java @@ -50,5 +50,15 @@ public void GetReturnsAllAvailableMetadataFormats() throws Exception { MetadataConfigsMatcher.matchMetadataConfigs(configs) ))) .andExpect(jsonPath("$._links.self.href", endsWith("/api/config/harvestermetadata"))); + + token = getAuthToken(eperson.getEmail(), password); + getClient(token).perform( + get("/api/config/harvestermetadata")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.allOf( + MetadataConfigsMatcher.matchMetadataConfigs(configs) + ))) + .andExpect(jsonPath("$._links.self.href", endsWith("/api/config/harvestermetadata"))); + } } From 56fc8d5741807bab5183fd47549a73d74b84e854 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 27 Sep 2019 16:13:42 +0200 Subject: [PATCH 22/23] Applied feedback --- .../java/org/dspace/app/rest/model/HarvestedCollectionRest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java index 2f6282ab6368..0b6049e4e120 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/HarvestedCollectionRest.java @@ -156,7 +156,7 @@ public void setLastHarvested(Date lastHarvested) { this.lastHarvested = lastHarvested; } - @LinkRest(linkClass = HarvesterMetadataRest.class, name = "metadata_configs", optional = true) + @LinkRest(linkClass = HarvesterMetadataRest.class, name = "harvestermetadata", optional = true) @JsonIgnore public HarvesterMetadataRest getMetadataConfigs() { return metadata_configs; From 2202195cfcb40960beb191c9ae2d707003ac65da Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 7 Oct 2019 16:07:23 +0200 Subject: [PATCH 23/23] Altered wrongly defined URL in CollectionHarvesterSettingsControllerIT --- .../app/rest/CollectionHarvestSettingsControllerIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java index 4751a49613f3..aaa9919e245c 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionHarvestSettingsControllerIT.java @@ -245,7 +245,7 @@ public void PutWorksWithStandardSettings() throws Exception { public void PutUnProcessableEntityIfIncorrectSettings() throws Exception { String token = getAuthToken(admin.getEmail(), password); - JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://dspace.mit.edu/iao/request", "col_1721.1_114174", "bc"); + JSONObject json = createHarvestSettingsJson("METADATA_ONLY", "https://mydspace.edu/oai/request", "col_1721.1_114174", "bc"); getClient(token).perform( put("/api/core/collections/" + collection.getID() + "/harvester") @@ -301,7 +301,7 @@ public void PutNotFoundIfNoSuchCollection() throws Exception { public void PutUnprocessableEntityIfHarvestTypeIncorrect() throws Exception { String token = getAuthToken(admin.getEmail(), password); - JSONObject json = createHarvestSettingsJson("INCORRECT_HARVEST_TYPE", "https://dspace.mit.edu/oai/request", "col_1721.1_114174", "dc"); + JSONObject json = createHarvestSettingsJson("INCORRECT_HARVEST_TYPE", "https://mydspace.edu/oai/request", "col_1721.1_114174", "dc"); getClient(token).perform( put("/api/core/collections/" + collection.getID() + "/harvester")