Merge remote-tracking branch 'upstream/main' into #2956

This commit is contained in:
Mark H. Wood
2020-11-30 17:24:48 -05:00
15 changed files with 704 additions and 107 deletions

View File

@@ -4,6 +4,13 @@
# Can be validated via instructions at: # Can be validated via instructions at:
# https://docs.codecov.io/docs/codecov-yaml#validate-your-repository-yaml # https://docs.codecov.io/docs/codecov-yaml#validate-your-repository-yaml
# Tell Codecov not to send a coverage notification until (at least) 2 builds are completed
# Since we run Unit & Integration tests in parallel, this lets Codecov know that coverage
# needs to be merged across those builds
codecov:
notify:
after_n_builds: 2
# Settings related to code coverage analysis # Settings related to code coverage analysis
coverage: coverage:
status: status:

65
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,65 @@
# DSpace Continuous Integration/Build via GitHub Actions
# Concepts borrowed from
# https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-java-with-maven
name: Build
# Run this Build for all pushes / PRs to current branch
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-latest
env:
# Give Maven 1GB of memory to work with
# Suppress all Maven "downloading" messages in Travis logs (see https://stackoverflow.com/a/35653426)
# This also slightly speeds builds, as there is less logging
MAVEN_OPTS: "-Xmx1024M -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
strategy:
# Create a matrix of two separate configurations for Unit vs Integration Tests
# This will ensure those tasks are run in parallel
matrix:
include:
# NOTE: Unit Tests include deprecated REST API v6 (as it has unit tests)
- type: "Unit Tests"
mvnflags: "-DskipUnitTests=false -Pdspace-rest"
# NOTE: ITs skip all code validation checks, as they are already done by Unit Test job.
# - enforcer.skip => Skip maven-enforcer-plugin rules
# - checkstyle.skip => Skip all checkstyle checks by maven-checkstyle-plugin
# - license.skip => Skip all license header checks by license-maven-plugin
# - xml.skip => Skip all XML/XSLT validation by xml-maven-plugin
- type: "Integration Tests"
mvnflags: "-DskipIntegrationTests=false -Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true"
# Do NOT exit immediately if one matrix job fails
# This ensures ITs continue running even if Unit Tests fail, or visa versa
fail-fast: false
# These are the actual CI steps to perform per job
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v1
# https://github.com/actions/setup-java
- name: Install JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
# https://github.com/actions/cache
- name: Cache Maven dependencies
uses: actions/cache@v2
with:
# Cache entire ~/.m2/repository
path: ~/.m2/repository
# Cache key is hash of all pom.xml files. Therefore any changes to POMs will invalidate cache
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
# Run parallel Maven builds based on the above 'strategy.matrix'
- name: Run Maven ${{ matrix.type }}
env:
TEST_FLAGS: ${{ matrix.mvnflags }}
run: mvn install -B -V -P-assembly -Pcoverage-report $TEST_FLAGS
# https://github.com/codecov/codecov-action
- name: Upload coverage to Codecov.io
uses: codecov/codecov-action@v1

View File

@@ -1,55 +0,0 @@
# DSpace's Travis CI Configuration
# Builds: https://travis-ci.com/github/DSpace/DSpace
# Travis configuration guide/validation: https://config.travis-ci.com/explore
language: java
# TODO: Upgrade to Bionic
dist: trusty
os: linux
jdk:
# DS-3384 Oracle JDK has DocLint enabled by default.
# Let's use this to catch any newly introduced DocLint issues.
- oraclejdk11
# Define global environment variables (shared across all jobs)
env:
global:
# Suppress all Maven "downloading" messages in Travis logs (see https://stackoverflow.com/a/35653426)
# This also slightly speeds builds in Travis, as there is less logging
- HIDE_MAVEN_DOWNLOADS="-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
# Give Maven 1GB of memory to work with
- MAVEN_OPTS="-Xmx1024M $HIDE_MAVEN_DOWNLOADS"
# Maven options which will skip ALL code validation checks. Includes skipping:
# - enforcer.skip => Skip maven-enforcer-plugin rules
# - checkstyle.skip => Skip all checkstyle checks by maven-checkstyle-plugin
# - license.skip => Skip all license header checks by license-maven-plugin
# - xml.skip => Skip all XML/XSLT validation by xml-maven-plugin
# (Useful for builds which don't need to repeat code checks)
- SKIP_CODE_CHECKS="-Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true"
# Create two jobs to run Unit & Integration tests in parallel.
# These jobs only differ in the TEST_FLAGS defined below,
# and otherwise share all the other configs in this file
jobs:
include:
- name: "Run Unit Tests & Check Code"
# NOTE: unit tests include deprecated REST API v6 (as it has unit tests)
env: TEST_FLAGS="-DskipUnitTests=false -Pdspace-rest"
- name: "Run Integration Tests"
# NOTE: skips code checks, as they are already done by Unit Test job
env: TEST_FLAGS="-DskipIntegrationTests=false $SKIP_CODE_CHECKS"
# Skip 'install' process to save time. We build/install/test all at once in "script" below.
install: skip
# Build DSpace and run configured tests (see 'jobs' above)
# Notes on flags used:
# -B => Maven batch/non-interactive mode (recommended for CI)
# -V => Display Maven version info before build
# -P-assembly => Disable build of dspace-installer in [src]/dspace/, as it can be memory intensive
# -Pcoverage-report => Enable aggregate code coverage report (across all modules) via JaCoCo
script: mvn install -B -V -P-assembly -Pcoverage-report $TEST_FLAGS
# After a successful build and test (see 'script'), send aggregate code coverage reports
# (generated by -Pcoverage-report above) to CodeCov.io
after_success: bash <(curl -s https://codecov.io/bash)

View File

@@ -1,7 +1,7 @@
# DSpace # DSpace
[![Build Status](https://travis-ci.com/DSpace/DSpace.png?branch=main)](https://travis-ci.com/DSpace/DSpace) [![Build Status](https://github.com/DSpace/DSpace/workflows/Build/badge.svg)](https://github.com/DSpace/DSpace/actions?query=workflow%3ABuild)
[DSpace Documentation](https://wiki.lyrasis.org/display/DSDOC/) | [DSpace Documentation](https://wiki.lyrasis.org/display/DSDOC/) |
[DSpace Releases](https://github.com/DSpace/DSpace/releases) | [DSpace Releases](https://github.com/DSpace/DSpace/releases) |
@@ -86,7 +86,7 @@ DSpace uses GitHub to track issues:
### Running Tests ### Running Tests
By default, in DSpace, Unit Tests and Integration Tests are disabled. However, they are By default, in DSpace, Unit Tests and Integration Tests are disabled. However, they are
run automatically by [Travis CI](https://travis-ci.com/DSpace/DSpace/) for all Pull Requests and code commits. run automatically by [GitHub Actions](https://github.com/DSpace/DSpace/actions?query=workflow%3ABuild) for all Pull Requests and code commits.
* How to run both Unit Tests (via `maven-surefire-plugin`) and Integration Tests (via `maven-failsafe-plugin`): * How to run both Unit Tests (via `maven-surefire-plugin`) and Integration Tests (via `maven-failsafe-plugin`):
``` ```

View File

@@ -842,12 +842,30 @@
<version>1.10.50</version> <version>1.10.50</version>
</dependency> </dependency>
<!-- For ORCID v2 integration -->
<dependency> <dependency>
<groupId>org.dspace</groupId> <groupId>org.orcid</groupId>
<artifactId>orcid-jaxb-api</artifactId> <artifactId>orcid-model</artifactId>
<version>2.1.0</version> <version>3.0.2</version>
<exclusions>
<exclusion>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</exclusion>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
<exclusion>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.json</groupId> <groupId>org.json</groupId>
<artifactId>json</artifactId> <artifactId>json</artifactId>

View File

@@ -37,6 +37,7 @@ public class OrcidRestConnector {
} }
public InputStream get(String path, String accessToken) { public InputStream get(String path, String accessToken) {
HttpResponse getResponse = null;
InputStream result = null; InputStream result = null;
path = trimSlashes(path); path = trimSlashes(path);
@@ -48,7 +49,7 @@ public class OrcidRestConnector {
} }
try { try {
HttpClient httpClient = HttpClientBuilder.create().build(); HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse getResponse = httpClient.execute(httpGet); getResponse = httpClient.execute(httpGet);
//do not close this httpClient //do not close this httpClient
result = getResponse.getEntity().getContent(); result = getResponse.getEntity().getContent();
} catch (Exception e) { } catch (Exception e) {
@@ -76,6 +77,4 @@ public class OrcidRestConnector {
Scanner s = new Scanner(is).useDelimiter("\\A"); Scanner s = new Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : ""; return s.hasNext() ? s.next() : "";
} }
} }

View File

@@ -32,30 +32,33 @@ import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider; import org.dspace.external.provider.ExternalDataProvider;
import org.dspace.external.provider.orcid.xml.XMLtoBio; import org.dspace.external.provider.orcid.xml.XMLtoBio;
import org.json.JSONObject; import org.json.JSONObject;
import org.orcid.jaxb.model.common_v2.OrcidId; import org.orcid.jaxb.model.v3.release.common.OrcidIdentifier;
import org.orcid.jaxb.model.record_v2.Person; import org.orcid.jaxb.model.v3.release.record.Person;
import org.orcid.jaxb.model.search_v2.Result; import org.orcid.jaxb.model.v3.release.search.Result;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
* This class is the implementation of the ExternalDataProvider interface that will deal with the OrcidV2 External * This class is the implementation of the ExternalDataProvider interface that will deal with the OrcidV3 External
* Data lookup * Data lookup
*/ */
public class OrcidV2AuthorDataProvider implements ExternalDataProvider { public class OrcidV3AuthorDataProvider implements ExternalDataProvider {
private static final Logger log = LogManager.getLogger(OrcidV2AuthorDataProvider.class); private static final Logger log = LogManager.getLogger(OrcidV3AuthorDataProvider.class);
private final OrcidRestConnector orcidRestConnector; private OrcidRestConnector orcidRestConnector;
private String OAUTHUrl; private String OAUTHUrl;
private String clientId;
private String clientId;
private String clientSecret; private String clientSecret;
private String accessToken; private String accessToken;
private String sourceIdentifier; private String sourceIdentifier;
private String orcidUrl; private String orcidUrl;
private XMLtoBio converter;
public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})"; public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})";
@Override @Override
@@ -63,13 +66,18 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
return sourceIdentifier; return sourceIdentifier;
} }
public OrcidV3AuthorDataProvider() {
converter = new XMLtoBio();
}
/** /**
* Initialize the accessToken that is required for all subsequent calls to ORCID. * Initialize the accessToken that is required for all subsequent calls to ORCID.
* *
* @throws java.io.IOException passed through from HTTPclient. * @throws java.io.IOException passed through from HTTPclient.
*/ */
public void init() throws IOException { public void init() throws IOException {
if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(clientSecret)) { if (StringUtils.isNotBlank(clientSecret) && StringUtils.isNotBlank(clientId)
&& StringUtils.isNotBlank(OAUTHUrl)) {
String authenticationParameters = "?client_id=" + clientId + String authenticationParameters = "?client_id=" + clientId +
"&client_secret=" + clientSecret + "&client_secret=" + clientSecret +
"&scope=/read-public&grant_type=client_credentials"; "&scope=/read-public&grant_type=client_credentials";
@@ -101,14 +109,6 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
} }
} }
/**
* Makes an instance of the Orcidv2 class based on the provided parameters.
* This constructor is called through the spring bean initialization
*/
private OrcidV2AuthorDataProvider(String url) {
this.orcidRestConnector = new OrcidRestConnector(url);
}
@Override @Override
public Optional<ExternalDataObject> getExternalDataObject(String id) { public Optional<ExternalDataObject> getExternalDataObject(String id) {
Person person = getBio(id); Person person = getBio(id);
@@ -121,12 +121,12 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
String lastName = ""; String lastName = "";
String firstName = ""; String firstName = "";
if (person.getName().getFamilyName() != null) { if (person.getName().getFamilyName() != null) {
lastName = person.getName().getFamilyName().getValue(); lastName = person.getName().getFamilyName().getContent();
externalDataObject.addMetadata(new MetadataValueDTO("person", "familyName", null, null, externalDataObject.addMetadata(new MetadataValueDTO("person", "familyName", null, null,
lastName)); lastName));
} }
if (person.getName().getGivenNames() != null) { if (person.getName().getGivenNames() != null) {
firstName = person.getName().getGivenNames().getValue(); firstName = person.getName().getGivenNames().getContent();
externalDataObject.addMetadata(new MetadataValueDTO("person", "givenName", null, null, externalDataObject.addMetadata(new MetadataValueDTO("person", "givenName", null, null,
firstName)); firstName));
@@ -150,7 +150,7 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
} }
/** /**
* Retrieve a Person object based on a given orcid identifier * Retrieve a Person object based on a given orcid identifier.
* @param id orcid identifier * @param id orcid identifier
* @return Person * @return Person
*/ */
@@ -160,7 +160,6 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
return null; return null;
} }
InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken); InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
XMLtoBio converter = new XMLtoBio();
Person person = converter.convertSinglePerson(bioDocument); Person person = converter.convertSinglePerson(bioDocument);
try { try {
bioDocument.close(); bioDocument.close();
@@ -190,14 +189,13 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
+ "&rows=" + limit; + "&rows=" + limit;
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken); log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken); InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken);
XMLtoBio converter = new XMLtoBio();
List<Result> results = converter.convert(bioDocument); List<Result> results = converter.convert(bioDocument);
List<Person> bios = new LinkedList<>(); List<Person> bios = new LinkedList<>();
for (Result result : results) { for (Result result : results) {
OrcidId orcidIdentifier = result.getOrcidIdentifier(); OrcidIdentifier orcidIdentifier = result.getOrcidIdentifier();
if (orcidIdentifier != null) { if (orcidIdentifier != null) {
log.debug("Found OrcidId=" + orcidIdentifier.toString()); log.debug("Found OrcidId=" + orcidIdentifier.toString());
String orcid = orcidIdentifier.getUriPath(); String orcid = orcidIdentifier.getPath();
Person bio = getBio(orcid); Person bio = getBio(orcid);
if (bio != null) { if (bio != null) {
bios.add(bio); bios.add(bio);
@@ -228,14 +226,13 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
+ "&rows=" + 0; + "&rows=" + 0;
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken); log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken); InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken);
XMLtoBio converter = new XMLtoBio();
return converter.getNumberOfResultsFromXml(bioDocument); return converter.getNumberOfResultsFromXml(bioDocument);
} }
/** /**
* Generic setter for the sourceIdentifier * Generic setter for the sourceIdentifier
* @param sourceIdentifier The sourceIdentifier to be set on this OrcidV2AuthorDataProvider * @param sourceIdentifier The sourceIdentifier to be set on this OrcidV3AuthorDataProvider
*/ */
@Autowired(required = true) @Autowired(required = true)
public void setSourceIdentifier(String sourceIdentifier) { public void setSourceIdentifier(String sourceIdentifier) {
@@ -244,7 +241,7 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
/** /**
* Generic getter for the orcidUrl * Generic getter for the orcidUrl
* @return the orcidUrl value of this OrcidV2AuthorDataProvider * @return the orcidUrl value of this OrcidV3AuthorDataProvider
*/ */
public String getOrcidUrl() { public String getOrcidUrl() {
return orcidUrl; return orcidUrl;
@@ -252,7 +249,7 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
/** /**
* Generic setter for the orcidUrl * Generic setter for the orcidUrl
* @param orcidUrl The orcidUrl to be set on this OrcidV2AuthorDataProvider * @param orcidUrl The orcidUrl to be set on this OrcidV3AuthorDataProvider
*/ */
@Autowired(required = true) @Autowired(required = true)
public void setOrcidUrl(String orcidUrl) { public void setOrcidUrl(String orcidUrl) {
@@ -261,7 +258,7 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
/** /**
* Generic setter for the OAUTHUrl * Generic setter for the OAUTHUrl
* @param OAUTHUrl The OAUTHUrl to be set on this OrcidV2AuthorDataProvider * @param OAUTHUrl The OAUTHUrl to be set on this OrcidV3AuthorDataProvider
*/ */
public void setOAUTHUrl(String OAUTHUrl) { public void setOAUTHUrl(String OAUTHUrl) {
this.OAUTHUrl = OAUTHUrl; this.OAUTHUrl = OAUTHUrl;
@@ -269,7 +266,7 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
/** /**
* Generic setter for the clientId * Generic setter for the clientId
* @param clientId The clientId to be set on this OrcidV2AuthorDataProvider * @param clientId The clientId to be set on this OrcidV3AuthorDataProvider
*/ */
public void setClientId(String clientId) { public void setClientId(String clientId) {
this.clientId = clientId; this.clientId = clientId;
@@ -277,9 +274,18 @@ public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
/** /**
* Generic setter for the clientSecret * Generic setter for the clientSecret
* @param clientSecret The clientSecret to be set on this OrcidV2AuthorDataProvider * @param clientSecret The clientSecret to be set on this OrcidV3AuthorDataProvider
*/ */
public void setClientSecret(String clientSecret) { public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
} }
public OrcidRestConnector getOrcidRestConnector() {
return orcidRestConnector;
}
public void setOrcidRestConnector(OrcidRestConnector orcidRestConnector) {
this.orcidRestConnector = orcidRestConnector;
}
} }

View File

@@ -13,11 +13,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.orcid.jaxb.model.record_v2.Person; import org.orcid.jaxb.model.v3.release.record.Person;
import org.orcid.jaxb.model.search_v2.Result; import org.orcid.jaxb.model.v3.release.search.Result;
import org.orcid.jaxb.model.search_v2.Search; import org.orcid.jaxb.model.v3.release.search.Search;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
/** /**
* @author Antoine Snyers (antoine at atmire.com) * @author Antoine Snyers (antoine at atmire.com)
* @author Kevin Van de Velde (kevin at atmire dot com) * @author Kevin Van de Velde (kevin at atmire dot com)
@@ -36,7 +37,7 @@ public class XMLtoBio extends Converter<List<Result>> {
List<Result> bios = new ArrayList<>(); List<Result> bios = new ArrayList<>();
try { try {
Search search = (Search) unmarshall(xml, Search.class); Search search = (Search) unmarshall(xml, Search.class);
bios = search.getResult(); bios = search.getResults();
} catch (SAXException | URISyntaxException e) { } catch (SAXException | URISyntaxException e) {
log.error(e); log.error(e);
} }
@@ -52,6 +53,7 @@ public class XMLtoBio extends Converter<List<Result>> {
} }
return 0; return 0;
} }
public Person convertSinglePerson(InputStream xml) { public Person convertSinglePerson(InputStream xml) {
Person person = null; Person person = null;
try { try {

View File

@@ -10,5 +10,17 @@
<property name="sourceIdentifier" value="mock"/> <property name="sourceIdentifier" value="mock"/>
</bean> </bean>
<bean class="org.dspace.external.provider.impl.OrcidV3AuthorDataProvider" init-method="init">
<property name="sourceIdentifier" value="orcid"/>
<property name="orcidUrl" value="${orcid.url}" />
<property name="clientId" value="${orcid.clientid}" />
<property name="clientSecret" value="${orcid.clientsecret}" />
<property name="OAUTHUrl" value="${orcid.oauth.url}" />
<property name="orcidRestConnector" ref="orcidRestConnector"/>
</bean>
<bean id="orcidRestConnector" class="org.dspace.external.OrcidRestConnector">
<constructor-arg value="${orcid.api.url}"/>
</bean>
</beans> </beans>

View File

@@ -24,10 +24,11 @@ public class ExternalSourcesRestControllerIT extends AbstractControllerIntegrati
public void findAllExternalSources() throws Exception { public void findAllExternalSources() throws Exception {
getClient().perform(get("/api/integration/externalsources")) getClient().perform(get("/api/integration/externalsources"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.externalsources", Matchers.hasItem( .andExpect(jsonPath("$._embedded.externalsources", Matchers.hasItems(
ExternalSourceMatcher.matchExternalSource("mock", "mock", false) ExternalSourceMatcher.matchExternalSource("mock", "mock", false),
ExternalSourceMatcher.matchExternalSource("orcid", "orcid", false)
))) )))
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1))); .andExpect(jsonPath("$.page.totalElements", Matchers.is(2)));
} }
@Test @Test

View File

@@ -0,0 +1,281 @@
/**
* 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 com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
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.io.InputStream;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.external.OrcidRestConnector;
import org.dspace.external.provider.impl.OrcidV3AuthorDataProvider;
import org.dspace.services.ConfigurationService;
import org.hamcrest.Matchers;
import org.junit.Assume;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This test suite includes static test with mock data and end to end test to
* verify the integration with ORCID as an External Source. The end to end test
* run only if the orcid.clientid property is configured but of course also
* orcid.clientsecret is needed to successful run the tests. This can be enabled
* setting the orcid credentials via env variables, see the comments in the
* override section of the config-definition.xml
*
* @author Mykhaylo Boychuk (4Science.it)
*
*/
public class OrcidExternalSourcesIT extends AbstractControllerIntegrationTest {
@Autowired
ConfigurationService configurationService;
@Autowired
private OrcidV3AuthorDataProvider orcidV3AuthorDataProvider;
public void onlyRunIfConfigExists() {
if (StringUtils.isBlank(configurationService.getProperty("orcid.clientid"))) {
Assume.assumeNoException(new IllegalStateException("Missing ORCID credentials"));
}
}
@Test
public void findOneExternalSourcesExistingSources() throws Exception {
getClient().perform(get("/api/integration/externalsources/orcid"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is("orcid")),
hasJsonPath("$.name", is("orcid")),
hasJsonPath("$.hierarchical", is(false)),
hasJsonPath("$.type", is("externalsource"))
)));
}
@Test
public void findOneExternalSourcesExistingSourcesWithentryValueTest() throws Exception {
// this test will query the real ORCID API if configured in the CI otherwise will be skipped
onlyRunIfConfigExists();
String entry = "0000-0002-9029-1854";
getClient().perform(get("/api/integration/externalsources/orcid/entryValues/" + entry))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(entry)),
hasJsonPath("$.display", is("Bollini, Andrea")),
hasJsonPath("$.value", is("Bollini, Andrea")),
hasJsonPath("$.externalSource", is("orcid")),
hasJsonPath("$.type", is("externalSourceEntry"))
)))
.andExpect(jsonPath("$.metadata['dc.identifier.uri'][0].value",is("https://orcid.org/" + entry)))
.andExpect(jsonPath("$.metadata['person.familyName'][0].value",is("Bollini")))
.andExpect(jsonPath("$.metadata['person.givenName'][0].value",is("Andrea")))
.andExpect(jsonPath("$.metadata['person.identifier.orcid'][0].value",is(entry)));
}
@Test
public void findOneExternalSourceEntriesApplicableQueryTest() throws Exception {
// this test will query the real ORCID API if configured in the CI otherwise will be skipped
onlyRunIfConfigExists();
String q = "orcid:0000-0002-9029-1854";
getClient().perform(get("/api/integration/externalsources/orcid/entries")
.param("query", q))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.externalSourceEntries[0]", Matchers.allOf(
hasJsonPath("$.id", is("0000-0002-9029-1854")),
hasJsonPath("$.display", is("Bollini, Andrea")),
hasJsonPath("$.value", is("Bollini, Andrea")),
hasJsonPath("$.externalSource", is("orcid")),
hasJsonPath("$.type", is("externalSourceEntry"))
)))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['dc.identifier.uri'][0].value",
is("https://orcid.org/0000-0002-9029-1854")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.familyName'][0].value",
is("Bollini")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.givenName'][0].value",
is("Andrea")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.identifier.orcid'][0].value",
is("0000-0002-9029-1854")));
}
@Test
public void findOneExternalSourceEntriesApplicableQueryFamilyNameAndGivenNamesTest() throws Exception {
// this test will query the real ORCID API if configured in the CI otherwise will be skipped
onlyRunIfConfigExists();
String q = "family-name:bollini AND given-names:andrea";
getClient().perform(get("/api/integration/externalsources/orcid/entries")
.param("query", q))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.externalSourceEntries", Matchers.hasItem(
Matchers.allOf(
hasJsonPath("$.id", is("0000-0002-9029-1854")),
hasJsonPath("$.display", is("Bollini, Andrea")),
hasJsonPath("$.value", is("Bollini, Andrea")),
hasJsonPath("$.externalSource", is("orcid")),
hasJsonPath("$.type", is("externalSourceEntry")))
)))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['dc.identifier.uri'][0].value",
is("https://orcid.org/0000-0002-9029-1854")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.familyName'][0].value",
is("Bollini")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.givenName'][0].value",
is("Andrea")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.identifier.orcid'][0].value",
is("0000-0002-9029-1854")));
}
@Test
/**
* This test uses mock data in the orcid-person-record.xml file to simulate the
* response from ORCID and verify that it is properly consumed and exposed by
* the REST API
*
* @throws Exception
*/
public void findOneExternalSourcesMockitoTest() throws Exception {
OrcidRestConnector orcidConnector = Mockito.mock(OrcidRestConnector.class);
OrcidRestConnector realConnector = orcidV3AuthorDataProvider.getOrcidRestConnector();
orcidV3AuthorDataProvider.setOrcidRestConnector(orcidConnector);
when(orcidConnector.get(ArgumentMatchers.endsWith("/person"), ArgumentMatchers.any()))
.thenAnswer(new Answer<InputStream>() {
public InputStream answer(InvocationOnMock invocation) {
return getClass().getResourceAsStream("orcid-person-record.xml");
}
});
String entry = "0000-0002-9029-1854";
getClient().perform(get("/api/integration/externalsources/orcid/entryValues/" + entry))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(entry)),
hasJsonPath("$.display", is("Bollini, Andrea")),
hasJsonPath("$.value", is("Bollini, Andrea")),
hasJsonPath("$.externalSource", is("orcid")),
hasJsonPath("$.type", is("externalSourceEntry"))
)));
orcidV3AuthorDataProvider.setOrcidRestConnector(realConnector);
}
@Test
/**
* This test uses mock data in the orcid-search.xml and orcid-person-record.xml
* file to simulate the response from ORCID and verify that it is properly
* consumed and exposed by the REST API. The orcid-search.xml file indeed
* contains the ORCID matching the user query, for each of them our integration
* need to grab details making a second call to the ORCID profile (this is due
* to the ORCID API structure and cannot be avoid)
*
* @throws Exception
*/
public void findOneExternalSourceEntriesApplicableQueryMockitoTest() throws Exception {
OrcidRestConnector orcidConnector = Mockito.mock(OrcidRestConnector.class);
OrcidRestConnector realConnector = orcidV3AuthorDataProvider.getOrcidRestConnector();
orcidV3AuthorDataProvider.setOrcidRestConnector(orcidConnector);
try {
when(orcidConnector.get(ArgumentMatchers.startsWith("search?"), ArgumentMatchers.any()))
.thenAnswer(new Answer<InputStream>() {
public InputStream answer(InvocationOnMock invocation) {
return getClass().getResourceAsStream("orcid-search.xml");
}
});
when(orcidConnector.get(ArgumentMatchers.endsWith("/person"), ArgumentMatchers.any()))
.thenAnswer(new Answer<InputStream>() {
public InputStream answer(InvocationOnMock invocation) {
return getClass().getResourceAsStream("orcid-person-record.xml");
}
});
String q = "orcid:0000-0002-9029-1854";
getClient().perform(get("/api/integration/externalsources/orcid/entries")
.param("query", q))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.externalSourceEntries[0]", Matchers.allOf(
hasJsonPath("$.id", is("0000-0002-9029-1854")),
hasJsonPath("$.display", is("Bollini, Andrea")),
hasJsonPath("$.value", is("Bollini, Andrea")),
hasJsonPath("$.externalSource", is("orcid")),
hasJsonPath("$.type", is("externalSourceEntry"))
)))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['dc.identifier.uri'][0].value",
is("https://orcid.org/0000-0002-9029-1854")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.familyName'][0].value",
is("Bollini")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.givenName'][0].value",
is("Andrea")))
.andExpect(jsonPath(
"$._embedded.externalSourceEntries[0].metadata['person.identifier.orcid'][0].value",
is("0000-0002-9029-1854")));
} finally {
orcidV3AuthorDataProvider.setOrcidRestConnector(realConnector);
}
}
@Test
/**
* This test uses mock data in the orcid-search.xml and orcid-person-record.xml
* file to simulate the response from ORCID and verify that it is properly
* consumed and exposed by the REST API. The orcid-search.xml file indeed
* contains the ORCID matching the user query, for each of them our integration
* need to grab details making a second call to the ORCID profile (this is due
* to the ORCID API structure and cannot be avoid)
*
* @throws Exception
*/
public void findOneExternalSourceEntriesApplicableQueryFamilyNameAndGivenNamesMockitoTest() throws Exception {
OrcidRestConnector orcidConnector = Mockito.mock(OrcidRestConnector.class);
OrcidRestConnector realConnector = orcidV3AuthorDataProvider.getOrcidRestConnector();
orcidV3AuthorDataProvider.setOrcidRestConnector(orcidConnector);
try {
when(orcidConnector.get(ArgumentMatchers.startsWith("search?"), ArgumentMatchers.any()))
.thenAnswer(new Answer<InputStream>() {
public InputStream answer(InvocationOnMock invocation) {
return getClass().getResourceAsStream("orcid-search.xml");
}
});
when(orcidConnector.get(ArgumentMatchers.endsWith("/person"), ArgumentMatchers.any()))
.thenAnswer(new Answer<InputStream>() {
public InputStream answer(InvocationOnMock invocation) {
return getClass().getResourceAsStream("orcid-person-record.xml");
}
});
String q = "family-name:bollini AND given-names:andrea";
getClient().perform(get("/api/integration/externalsources/orcid/entries")
.param("query", q))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.externalSourceEntries", Matchers.hasItem(
Matchers.allOf(
hasJsonPath("$.id", is("0000-0002-9029-1854")),
hasJsonPath("$.display", is("Bollini, Andrea")),
hasJsonPath("$.value", is("Bollini, Andrea")),
hasJsonPath("$.externalSource", is("orcid")),
hasJsonPath("$.type", is("externalSourceEntry")))
)))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['dc.identifier.uri'][0].value",
is("https://orcid.org/0000-0002-9029-1854")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.familyName'][0].value",
is("Bollini")))
.andExpect(jsonPath("$._embedded.externalSourceEntries[0].metadata['person.givenName'][0].value",
is("Andrea")))
.andExpect(jsonPath(
"$._embedded.externalSourceEntries[0].metadata['person.identifier.orcid'][0].value",
is("0000-0002-9029-1854")));
} finally {
orcidV3AuthorDataProvider.setOrcidRestConnector(realConnector);
}
}
}

View File

@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person:person path="/0000-0002-9029-1854/person" xmlns:internal="http://www.orcid.org/ns/internal" xmlns:education="http://www.orcid.org/ns/education" xmlns:distinction="http://www.orcid.org/ns/distinction" xmlns:deprecated="http://www.orcid.org/ns/deprecated" xmlns:other-name="http://www.orcid.org/ns/other-name" xmlns:membership="http://www.orcid.org/ns/membership" xmlns:error="http://www.orcid.org/ns/error" xmlns:common="http://www.orcid.org/ns/common" xmlns:record="http://www.orcid.org/ns/record" xmlns:personal-details="http://www.orcid.org/ns/personal-details" xmlns:keyword="http://www.orcid.org/ns/keyword" xmlns:email="http://www.orcid.org/ns/email" xmlns:external-identifier="http://www.orcid.org/ns/external-identifier" xmlns:funding="http://www.orcid.org/ns/funding" xmlns:preferences="http://www.orcid.org/ns/preferences" xmlns:address="http://www.orcid.org/ns/address" xmlns:invited-position="http://www.orcid.org/ns/invited-position" xmlns:work="http://www.orcid.org/ns/work" xmlns:history="http://www.orcid.org/ns/history" xmlns:employment="http://www.orcid.org/ns/employment" xmlns:qualification="http://www.orcid.org/ns/qualification" xmlns:service="http://www.orcid.org/ns/service" xmlns:person="http://www.orcid.org/ns/person" xmlns:activities="http://www.orcid.org/ns/activities" xmlns:researcher-url="http://www.orcid.org/ns/researcher-url" xmlns:peer-review="http://www.orcid.org/ns/peer-review" xmlns:bulk="http://www.orcid.org/ns/bulk" xmlns:research-resource="http://www.orcid.org/ns/research-resource">
<common:last-modified-date>2018-02-05T23:27:36.636Z</common:last-modified-date>
<person:name visibility="public" path="0000-0002-9029-1854">
<common:created-date>2016-04-15T23:17:03.663Z</common:created-date>
<common:last-modified-date>2016-04-15T23:17:03.663Z</common:last-modified-date>
<personal-details:given-names>Andrea</personal-details:given-names>
<personal-details:family-name>Bollini</personal-details:family-name>
</person:name>
<other-name:other-names path="/0000-0002-9029-1854/other-names"/>
<researcher-url:researcher-urls path="/0000-0002-9029-1854/researcher-urls">
<common:last-modified-date>2017-07-18T15:10:48.940Z</common:last-modified-date>
<researcher-url:researcher-url put-code="1005571" visibility="public" path="/0000-0002-9029-1854/researcher-urls/1005571" display-index="5">
<common:created-date>2017-01-16T08:12:12.946Z</common:created-date>
<common:last-modified-date>2017-07-18T15:10:48.940Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<researcher-url:url-name>Linkedin</researcher-url:url-name>
<researcher-url:url>https://it.linkedin.com/in/andreabollini</researcher-url:url>
</researcher-url:researcher-url>
<researcher-url:researcher-url put-code="369007" visibility="public" path="/0000-0002-9029-1854/researcher-urls/369007" display-index="4">
<common:created-date>2014-11-06T10:37:30.383Z</common:created-date>
<common:last-modified-date>2017-07-18T15:10:48.940Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<researcher-url:url-name>4Science</researcher-url:url-name>
<researcher-url:url>http://www.4science.it/en/</researcher-url:url>
</researcher-url:researcher-url>
<researcher-url:researcher-url put-code="369009" visibility="public" path="/0000-0002-9029-1854/researcher-urls/369009" display-index="3">
<common:created-date>2014-11-06T10:37:30.412Z</common:created-date>
<common:last-modified-date>2017-07-18T15:10:48.940Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<researcher-url:url-name>DSpace</researcher-url:url-name>
<researcher-url:url>http://www.dspace.org</researcher-url:url>
</researcher-url:researcher-url>
<researcher-url:researcher-url put-code="369008" visibility="public" path="/0000-0002-9029-1854/researcher-urls/369008" display-index="2">
<common:created-date>2014-11-06T10:37:30.398Z</common:created-date>
<common:last-modified-date>2017-07-18T15:10:48.940Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<researcher-url:url-name>DSpace-CRIS</researcher-url:url-name>
<researcher-url:url>https://wiki.duraspace.org/display/DSPACECRIS</researcher-url:url>
</researcher-url:researcher-url>
</researcher-url:researcher-urls>
<email:emails path="/0000-0002-9029-1854/email">
<common:last-modified-date>2016-09-12T11:22:47.354Z</common:last-modified-date>
<email:email visibility="public" verified="true" primary="true">
<common:created-date>2016-09-12T10:45:26.123Z</common:created-date>
<common:last-modified-date>2016-09-12T11:22:47.354Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<email:email>andrea.bollini@4science.it</email:email>
</email:email>
</email:emails>
<address:addresses path="/0000-0002-9029-1854/address">
<common:last-modified-date>2016-06-06T15:29:36.952Z</common:last-modified-date>
<address:address put-code="240615" visibility="public" path="/0000-0002-9029-1854/address/240615" display-index="0">
<common:created-date>2016-01-24T18:24:26.704Z</common:created-date>
<common:last-modified-date>2016-06-06T15:29:36.952Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<address:country>IT</address:country>
</address:address>
</address:addresses>
<keyword:keywords path="/0000-0002-9029-1854/keywords">
<common:last-modified-date>2016-03-01T11:03:22.508Z</common:last-modified-date>
<keyword:keyword put-code="7508" visibility="public" path="/0000-0002-9029-1854/keywords/7508" display-index="3">
<common:created-date>2013-05-30T10:55:45.614Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.508Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content>Software</keyword:content>
</keyword:keyword>
<keyword:keyword put-code="7509" visibility="public" path="/0000-0002-9029-1854/keywords/7509" display-index="2">
<common:created-date>2013-05-30T10:55:45.614Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.508Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content> Open Source</keyword:content>
</keyword:keyword>
<keyword:keyword put-code="12596" visibility="public" path="/0000-0002-9029-1854/keywords/12596" display-index="1">
<common:created-date>2013-05-30T10:55:45.614Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.508Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content> JAVA</keyword:content>
</keyword:keyword>
<keyword:keyword put-code="381655" visibility="public" path="/0000-0002-9029-1854/keywords/381655" display-index="0">
<common:created-date>2016-03-01T11:03:22.491Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.491Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content>CERIF</keyword:content>
</keyword:keyword>
<keyword:keyword put-code="381656" visibility="public" path="/0000-0002-9029-1854/keywords/381656" display-index="0">
<common:created-date>2016-03-01T11:03:22.502Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.502Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content>CRIS</keyword:content>
</keyword:keyword>
<keyword:keyword put-code="381657" visibility="public" path="/0000-0002-9029-1854/keywords/381657" display-index="0">
<common:created-date>2016-03-01T11:03:22.503Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.503Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content>RIMS</keyword:content>
</keyword:keyword>
<keyword:keyword put-code="381658" visibility="public" path="/0000-0002-9029-1854/keywords/381658" display-index="0">
<common:created-date>2016-03-01T11:03:22.504Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.504Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content>Open Standards</keyword:content>
</keyword:keyword>
<keyword:keyword put-code="381659" visibility="public" path="/0000-0002-9029-1854/keywords/381659" display-index="0">
<common:created-date>2016-03-01T11:03:22.505Z</common:created-date>
<common:last-modified-date>2016-03-01T11:03:22.505Z</common:last-modified-date>
<common:source>
<common:source-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:source-orcid>
<common:source-name>Andrea Bollini</common:source-name>
</common:source>
<keyword:content>OAI-PMH</keyword:content>
</keyword:keyword>
</keyword:keywords>
<external-identifier:external-identifiers path="/0000-0002-9029-1854/external-identifiers">
<common:last-modified-date>2018-02-05T23:27:36.636Z</common:last-modified-date>
<external-identifier:external-identifier put-code="153301" visibility="public" path="/0000-0002-9029-1854/external-identifiers/153301" display-index="0">
<common:created-date>2013-05-30T10:55:45.614Z</common:created-date>
<common:last-modified-date>2018-02-05T23:27:36.636Z</common:last-modified-date>
<common:source>
<common:source-client-id>
<common:uri>https://orcid.org/client/0000-0002-5982-8983</common:uri>
<common:path>0000-0002-5982-8983</common:path>
<common:host>orcid.org</common:host>
</common:source-client-id>
<common:source-name>Scopus - Elsevier</common:source-name>
<common:assertion-origin-orcid>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:assertion-origin-orcid>
<common:assertion-origin-name>Andrea Bollini</common:assertion-origin-name>
</common:source>
<common:external-id-type>Scopus Author ID</common:external-id-type>
<common:external-id-value>55484808800</common:external-id-value>
<common:external-id-url>http://www.scopus.com/inward/authorDetails.url?authorID=55484808800&amp;partnerID=MN8TOARS</common:external-id-url>
<common:external-id-relationship>self</common:external-id-relationship>
</external-identifier:external-identifier>
</external-identifier:external-identifiers>
</person:person>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<search:search num-found="1" xmlns:search="http://www.orcid.org/ns/search" xmlns:common="http://www.orcid.org/ns/common">
<search:result>
<common:orcid-identifier>
<common:uri>https://orcid.org/0000-0002-9029-1854</common:uri>
<common:path>0000-0002-9029-1854</common:path>
<common:host>orcid.org</common:host>
</common:orcid-identifier>
</search:result>
</search:search>

View File

@@ -1473,10 +1473,20 @@ sherpa.romeo.apikey =
# org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority # org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority
# URL of ORCID API # URL of ORCID API
# Defaults to using the Public API (pub.orcid.org) # Defaults to using the Public API V3 (pub.orcid.org)
orcid.api.url = https://pub.orcid.org/v2.1 orcid.api.url = https://pub.orcid.org/v3.0
orcid.url = https://orcid.org/ orcid.url = https://orcid.org/
# ORCID Credentials
# Your public or member API Credentials, see
# https://orcid.org/content/register-client-application-0
orcid.clientid =
orcid.clientsecret =
#ORCID JWT Endpoint
orcid.oauth.url = https://orcid.org/oauth/token
## The DCInputAuthority plugin is automatically configured with every ## The DCInputAuthority plugin is automatically configured with every
## value-pairs element in input-forms.xml, namely: ## value-pairs element in input-forms.xml, namely:
## common_identifiers, common_types, common_iso_languages ## common_identifiers, common_types, common_iso_languages

View File

@@ -20,10 +20,17 @@
<property name="apiKey" value="${sherpa.romeo.apikey}"/> <property name="apiKey" value="${sherpa.romeo.apikey}"/>
</bean> </bean>
<bean class="org.dspace.external.provider.impl.OrcidV2AuthorDataProvider" init-method="init"> <bean class="org.dspace.external.provider.impl.OrcidV3AuthorDataProvider" init-method="init">
<constructor-arg value="${orcid.api.url}"/> <property name="sourceIdentifier" value="orcid"/>
<property name="sourceIdentifier" value="orcidV2"/>
<property name="orcidUrl" value="${orcid.url}" /> <property name="orcidUrl" value="${orcid.url}" />
<property name="clientId" value="${orcid.clientid}" />
<property name="clientSecret" value="${orcid.clientsecret}" />
<property name="OAUTHUrl" value="${orcid.oauth.url}" />
<property name="orcidRestConnector" ref="orcidRestConnector"/>
</bean>
<bean id="orcidRestConnector" class="org.dspace.external.OrcidRestConnector">
<constructor-arg value="${orcid.api.url}"/>
</bean> </bean>
<bean class="org.dspace.external.provider.impl.LCNameDataProvider"> <bean class="org.dspace.external.provider.impl.LCNameDataProvider">