mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 18:14:26 +00:00
[CST-5588] ORCID settings (REST) .
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.orcid.model;
|
||||
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
|
||||
/**
|
||||
* The entity types of the ORCID objects that can be synchronized.
|
||||
*
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||
*
|
||||
*/
|
||||
public enum OrcidEntityType {
|
||||
|
||||
PUBLICATION("/work"),
|
||||
FUNDING("/funding");
|
||||
|
||||
private final String path;
|
||||
|
||||
private OrcidEntityType(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public static boolean isValid(String entityType) {
|
||||
return entityType != null ? EnumUtils.isValidEnum(OrcidEntityType.class, entityType.toUpperCase()) : false;
|
||||
}
|
||||
|
||||
public static OrcidEntityType fromString(String entityType) {
|
||||
return isValid(entityType) ? OrcidEntityType.valueOf(entityType.toUpperCase()) : null;
|
||||
}
|
||||
}
|
@@ -8,9 +8,15 @@
|
||||
package org.dspace.app.orcid.service;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.dspace.app.orcid.model.OrcidEntityType;
|
||||
import org.dspace.app.orcid.model.OrcidTokenResponseDTO;
|
||||
import org.dspace.app.profile.OrcidEntitySyncPreference;
|
||||
import org.dspace.app.profile.OrcidProfileDisconnectionMode;
|
||||
import org.dspace.app.profile.OrcidProfileSyncPreference;
|
||||
import org.dspace.app.profile.OrcidSynchronizationMode;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
@@ -22,6 +28,14 @@ import org.dspace.core.Context;
|
||||
*/
|
||||
public interface OrcidSynchronizationService {
|
||||
|
||||
/**
|
||||
* Check if the given item is linked to an ORCID profile.
|
||||
*
|
||||
* @param item the item to check
|
||||
* @return true if the given item is linked to ORCID
|
||||
*/
|
||||
boolean isLinkedToOrcid(Item item);
|
||||
|
||||
/**
|
||||
* Configure the given profile with the data present in the given ORCID token.
|
||||
* This action is required to synchronize profile and related entities with
|
||||
@@ -43,6 +57,83 @@ public interface OrcidSynchronizationService {
|
||||
*/
|
||||
public void unlinkProfile(Context context, Item profile) throws SQLException;
|
||||
|
||||
/**
|
||||
* Set the synchronization preference for the given profile related to the given
|
||||
* ORCID entity type.
|
||||
*
|
||||
* @param context the relevant DSpace Context.
|
||||
* @param profile the researcher profile to update
|
||||
* @param entityType the orcid entity type
|
||||
* @param value the new synchronization preference value
|
||||
* @return true if the value has actually been updated,
|
||||
* false if the value to be set is the same as
|
||||
* the one already configured
|
||||
* @throws SQLException if a SQL error occurs during the profile
|
||||
* update
|
||||
* @throws IllegalArgumentException if the given researcher profile is no linked
|
||||
* with an ORCID account
|
||||
*/
|
||||
public boolean setEntityPreference(Context context, Item profile, OrcidEntityType entityType,
|
||||
OrcidEntitySyncPreference value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Update the profile's synchronization preference for the given profile.
|
||||
*
|
||||
* @param context the relevant DSpace Context.
|
||||
* @param profile the researcher profile to update
|
||||
* @param value the new synchronization preference value
|
||||
* @return true if the value has actually been updated,
|
||||
* false if the value to be set is the same as
|
||||
* the one already configured
|
||||
* @throws SQLException if a SQL error occurs during the profile
|
||||
* update
|
||||
* @throws IllegalArgumentException if the given researcher profile is no linked
|
||||
* with an ORCID account
|
||||
*/
|
||||
public boolean setProfilePreference(Context context, Item profile,
|
||||
List<OrcidProfileSyncPreference> values) throws SQLException;
|
||||
|
||||
/**
|
||||
* Set the ORCID synchronization mode for the given profile.
|
||||
*
|
||||
* @param context the relevant DSpace Context.
|
||||
* @param profile the researcher profile to update
|
||||
* @param value the new synchronization mode value
|
||||
* @return true if the value has actually been updated, false if
|
||||
* the value to be set is the same as the one already
|
||||
* configured
|
||||
* @throws SQLException if a SQL error occurs during the profile update
|
||||
*/
|
||||
public boolean setSynchronizationMode(Context context, Item profile, OrcidSynchronizationMode value)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Returns the ORCID synchronization mode configured for the given profile item.
|
||||
*
|
||||
* @param profile the researcher profile item
|
||||
* @return the synchronization mode
|
||||
*/
|
||||
Optional<OrcidSynchronizationMode> getSynchronizationMode(Item profile);
|
||||
|
||||
/**
|
||||
* Returns the ORCID synchronization preference related to the given entity type
|
||||
* configured for the given profile item.
|
||||
*
|
||||
* @param profile the researcher profile item
|
||||
* @param entityType the orcid entity type
|
||||
* @return the configured preference
|
||||
*/
|
||||
Optional<OrcidEntitySyncPreference> getEntityPreference(Item profile, OrcidEntityType entityType);
|
||||
|
||||
/**
|
||||
* Returns the ORCID synchronization preferences related to the profile itself
|
||||
* configured for the given profile item.
|
||||
*
|
||||
* @param profile the researcher profile item
|
||||
* @return the synchronization mode
|
||||
*/
|
||||
List<OrcidProfileSyncPreference> getProfilePreferences(Item profile);
|
||||
|
||||
/**
|
||||
* Returns the configuration ORCID profile's disconnection mode. If that mode is
|
||||
* not configured or the configuration is wrong, the value DISABLED is returned.
|
||||
|
@@ -9,14 +9,26 @@ package org.dspace.app.orcid.service.impl;
|
||||
|
||||
import static java.time.LocalDateTime.now;
|
||||
import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
|
||||
import static java.util.List.of;
|
||||
import static org.apache.commons.lang3.EnumUtils.isValidEnum;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.dspace.content.Item.ANY;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
import org.dspace.app.orcid.model.OrcidEntityType;
|
||||
import org.dspace.app.orcid.model.OrcidTokenResponseDTO;
|
||||
import org.dspace.app.orcid.service.OrcidSynchronizationService;
|
||||
import org.dspace.app.profile.OrcidEntitySyncPreference;
|
||||
import org.dspace.app.profile.OrcidProfileDisconnectionMode;
|
||||
import org.dspace.app.profile.OrcidProfileSyncPreference;
|
||||
import org.dspace.app.profile.OrcidSynchronizationMode;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
@@ -88,6 +100,77 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setEntityPreference(Context context, Item profile, OrcidEntityType type,
|
||||
OrcidEntitySyncPreference value) throws SQLException {
|
||||
String metadataQualifier = "sync-" + type.name().toLowerCase() + "s";
|
||||
return updatePreferenceForSynchronizingWithOrcid(context, profile, metadataQualifier, of(value.name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setProfilePreference(Context context, Item profile, List<OrcidProfileSyncPreference> values)
|
||||
throws SQLException {
|
||||
|
||||
List<String> valuesAsString = values.stream()
|
||||
.map(OrcidProfileSyncPreference::name)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return updatePreferenceForSynchronizingWithOrcid(context, profile, "sync-profile", valuesAsString);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSynchronizationMode(Context context, Item profile, OrcidSynchronizationMode value)
|
||||
throws SQLException {
|
||||
|
||||
if (!isLinkedToOrcid(profile)) {
|
||||
throw new IllegalArgumentException("The given profile cannot be configured for the ORCID "
|
||||
+ "synchronization because it is not linked to any ORCID account: "
|
||||
+ profile.getID());
|
||||
}
|
||||
|
||||
String newValue = value.name();
|
||||
String oldValue = itemService.getMetadataFirstValue(profile, "dspace", "orcid", "sync-mode", Item.ANY);
|
||||
|
||||
if (StringUtils.equals(oldValue, newValue)) {
|
||||
return false;
|
||||
} else {
|
||||
itemService.setMetadataSingleValue(context, profile, "dspace", "orcid", "sync-mode", null, value.name());
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<OrcidSynchronizationMode> getSynchronizationMode(Item item) {
|
||||
return getMetadataValue(item, "dspace.orcid.sync-mode")
|
||||
.map(metadataValue -> metadataValue.getValue())
|
||||
.filter(value -> isValidEnum(OrcidSynchronizationMode.class, value))
|
||||
.map(value -> OrcidSynchronizationMode.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<OrcidEntitySyncPreference> getEntityPreference(Item item, OrcidEntityType entityType) {
|
||||
return getMetadataValue(item, "dspace.orcid.sync-" + entityType.name().toLowerCase() + "s")
|
||||
.map(metadataValue -> metadataValue.getValue())
|
||||
.filter(value -> isValidEnum(OrcidEntitySyncPreference.class, value))
|
||||
.map(value -> OrcidEntitySyncPreference.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrcidProfileSyncPreference> getProfilePreferences(Item item) {
|
||||
return getMetadataValues(item, "dspace.orcid.sync-profile")
|
||||
.map(MetadataValue::getValue)
|
||||
.filter(value -> isValidEnum(OrcidProfileSyncPreference.class, value))
|
||||
.map(value -> OrcidProfileSyncPreference.valueOf(value))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLinkedToOrcid(Item item) {
|
||||
return getOrcidAccessToken(item).isPresent() && getOrcid(item).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrcidProfileDisconnectionMode getDisconnectionMode() {
|
||||
String value = configurationService.getProperty("orcid.disconnection.allowed-users");
|
||||
@@ -97,11 +180,60 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
|
||||
return OrcidProfileDisconnectionMode.fromString(value);
|
||||
}
|
||||
|
||||
private boolean updatePreferenceForSynchronizingWithOrcid(Context context, Item profile,
|
||||
String metadataQualifier,
|
||||
List<String> values) throws SQLException {
|
||||
|
||||
if (!isLinkedToOrcid(profile)) {
|
||||
throw new IllegalArgumentException("The given profile cannot be configured for the ORCID "
|
||||
+ "synchronization because it is not linked to any ORCID account: "
|
||||
+ profile.getID());
|
||||
}
|
||||
|
||||
List<String> oldValues = itemService.getMetadata(profile, "dspace", "orcid", metadataQualifier, ANY).stream()
|
||||
.map(metadataValue -> metadataValue.getValue())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (containsSameValues(oldValues, values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
itemService.clearMetadata(context, profile, "dspace", "orcid", metadataQualifier, ANY);
|
||||
for (String value : values) {
|
||||
itemService.addMetadata(context, profile, "dspace", "orcid", metadataQualifier, null, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private boolean containsSameValues(List<String> firstList, List<String> secondList) {
|
||||
return new HashSet<>(firstList).equals(new HashSet<>(secondList));
|
||||
}
|
||||
|
||||
private Optional<String> getOrcidAccessToken(Item item) {
|
||||
return getMetadataValue(item, "dspace.orcid.access-token")
|
||||
.map(metadataValue -> metadataValue.getValue());
|
||||
}
|
||||
|
||||
public Optional<String> getOrcid(Item item) {
|
||||
return getMetadataValue(item, "person.identifier.orcid")
|
||||
.map(metadataValue -> metadataValue.getValue());
|
||||
}
|
||||
|
||||
private Optional<MetadataValue> getMetadataValue(Item item, String metadataField) {
|
||||
return getMetadataValues(item, metadataField).findFirst();
|
||||
}
|
||||
|
||||
private Stream<MetadataValue> getMetadataValues(Item item, String metadataField) {
|
||||
return item.getMetadata().stream()
|
||||
.filter(metadata -> metadataField.equals(metadata.getMetadataField().toString('.')));
|
||||
}
|
||||
|
||||
private String getProfileType() {
|
||||
return configurationService.getProperty("researcher-profile.type", "Person");
|
||||
}
|
||||
|
||||
private void updateItem(Context context, Item item) throws SQLException {
|
||||
try {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.profile;
|
||||
|
||||
/**
|
||||
* Enum that model the allowed values to configure the ORCID synchronization
|
||||
* preferences.
|
||||
*
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||
*
|
||||
*/
|
||||
public enum OrcidEntitySyncPreference {
|
||||
|
||||
DISABLED,
|
||||
ALL
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.profile;
|
||||
|
||||
/**
|
||||
* Enum that model the allowed values to configure the ORCID synchronization
|
||||
* preferences for the user's profile.
|
||||
*
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||
*
|
||||
*/
|
||||
public enum OrcidProfileSyncPreference {
|
||||
|
||||
BIOGRAPHICAL,
|
||||
IDENTIFIERS;
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.profile;
|
||||
|
||||
/**
|
||||
* Enum that model the allowed values to configure the ORCID synchronization
|
||||
* mode.
|
||||
*
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||
*
|
||||
*/
|
||||
public enum OrcidSynchronizationMode {
|
||||
|
||||
MANUAL,
|
||||
BATCH;
|
||||
}
|
@@ -62,6 +62,11 @@ public class ResearcherProfile {
|
||||
return item;
|
||||
}
|
||||
|
||||
public Optional<String> getOrcid() {
|
||||
return getMetadataValue(item, "person.identifier.orcid")
|
||||
.map(metadataValue -> metadataValue.getValue());
|
||||
}
|
||||
|
||||
private MetadataValue getDspaceObjectOwnerMetadata(Item item) {
|
||||
return getMetadataValue(item, "dspace.object.owner")
|
||||
.filter(metadata -> UUIDUtils.fromString(metadata.getAuthority()) != null)
|
||||
|
@@ -7,10 +7,22 @@
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import static org.dspace.app.orcid.model.OrcidEntityType.FUNDING;
|
||||
import static org.dspace.app.orcid.model.OrcidEntityType.PUBLICATION;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.dspace.app.orcid.service.OrcidSynchronizationService;
|
||||
import org.dspace.app.profile.OrcidEntitySyncPreference;
|
||||
import org.dspace.app.profile.OrcidProfileSyncPreference;
|
||||
import org.dspace.app.profile.OrcidSynchronizationMode;
|
||||
import org.dspace.app.profile.ResearcherProfile;
|
||||
import org.dspace.app.rest.model.ResearcherProfileRest;
|
||||
import org.dspace.app.rest.model.ResearcherProfileRest.OrcidSynchronizationRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.Item;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -23,6 +35,9 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class ResearcherProfileConverter implements DSpaceConverter<ResearcherProfile, ResearcherProfileRest> {
|
||||
|
||||
@Autowired
|
||||
private OrcidSynchronizationService orcidSynchronizationService;
|
||||
|
||||
@Override
|
||||
public ResearcherProfileRest convert(ResearcherProfile profile, Projection projection) {
|
||||
ResearcherProfileRest researcherProfileRest = new ResearcherProfileRest();
|
||||
@@ -33,9 +48,44 @@ public class ResearcherProfileConverter implements DSpaceConverter<ResearcherPro
|
||||
|
||||
Item item = profile.getItem();
|
||||
|
||||
if (orcidSynchronizationService.isLinkedToOrcid(item)) {
|
||||
profile.getOrcid().ifPresent(researcherProfileRest::setOrcid);
|
||||
|
||||
OrcidSynchronizationRest orcidSynchronization = new OrcidSynchronizationRest();
|
||||
orcidSynchronization.setMode(getMode(item));
|
||||
orcidSynchronization.setProfilePreferences(getProfilePreferences(item));
|
||||
orcidSynchronization.setFundingsPreference(getFundingsPreference(item));
|
||||
orcidSynchronization.setPublicationsPreference(getPublicationsPreference(item));
|
||||
researcherProfileRest.setOrcidSynchronization(orcidSynchronization);
|
||||
}
|
||||
|
||||
return researcherProfileRest;
|
||||
}
|
||||
|
||||
private String getPublicationsPreference(Item item) {
|
||||
return orcidSynchronizationService.getEntityPreference(item, PUBLICATION)
|
||||
.map(OrcidEntitySyncPreference::name)
|
||||
.orElse(OrcidEntitySyncPreference.DISABLED.name());
|
||||
}
|
||||
|
||||
private String getFundingsPreference(Item item) {
|
||||
return orcidSynchronizationService.getEntityPreference(item, FUNDING)
|
||||
.map(OrcidEntitySyncPreference::name)
|
||||
.orElse(OrcidEntitySyncPreference.DISABLED.name());
|
||||
}
|
||||
|
||||
private List<String> getProfilePreferences(Item item) {
|
||||
return orcidSynchronizationService.getProfilePreferences(item).stream()
|
||||
.map(OrcidProfileSyncPreference::name)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String getMode(Item item) {
|
||||
return orcidSynchronizationService.getSynchronizationMode(item)
|
||||
.map(OrcidSynchronizationMode::name)
|
||||
.orElse(OrcidSynchronizationMode.MANUAL.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ResearcherProfile> getModelClass() {
|
||||
return ResearcherProfile.class;
|
||||
|
@@ -7,8 +7,10 @@
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
@@ -32,6 +34,12 @@ public class ResearcherProfileRest extends BaseObjectRest<UUID> {
|
||||
|
||||
private boolean visible;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String orcid;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private OrcidSynchronizationRest orcidSynchronization;
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
@@ -40,6 +48,22 @@ public class ResearcherProfileRest extends BaseObjectRest<UUID> {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
public OrcidSynchronizationRest getOrcidSynchronization() {
|
||||
return orcidSynchronization;
|
||||
}
|
||||
|
||||
public void setOrcidSynchronization(OrcidSynchronizationRest orcidSynchronization) {
|
||||
this.orcidSynchronization = orcidSynchronization;
|
||||
}
|
||||
|
||||
public String getOrcid() {
|
||||
return orcid;
|
||||
}
|
||||
|
||||
public void setOrcid(String orcid) {
|
||||
this.orcid = orcid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return NAME;
|
||||
@@ -54,4 +78,55 @@ public class ResearcherProfileRest extends BaseObjectRest<UUID> {
|
||||
public Class<?> getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class to model ORCID synchronization preferences and mode.
|
||||
*
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||
*
|
||||
*/
|
||||
public static class OrcidSynchronizationRest {
|
||||
|
||||
private String mode;
|
||||
|
||||
private String publicationsPreference;
|
||||
|
||||
private String fundingsPreference;
|
||||
|
||||
private List<String> profilePreferences;
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public List<String> getProfilePreferences() {
|
||||
return profilePreferences;
|
||||
}
|
||||
|
||||
public void setProfilePreferences(List<String> profilePreferences) {
|
||||
this.profilePreferences = profilePreferences;
|
||||
}
|
||||
|
||||
public String getPublicationsPreference() {
|
||||
return publicationsPreference;
|
||||
}
|
||||
|
||||
public void setPublicationsPreference(String publicationsPreference) {
|
||||
this.publicationsPreference = publicationsPreference;
|
||||
}
|
||||
|
||||
public String getFundingsPreference() {
|
||||
return fundingsPreference;
|
||||
}
|
||||
|
||||
public void setFundingsPreference(String fundingsPreference) {
|
||||
this.fundingsPreference = fundingsPreference;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* 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.patch.operation;
|
||||
|
||||
import static org.dspace.app.orcid.model.OrcidEntityType.FUNDING;
|
||||
import static org.dspace.app.orcid.model.OrcidEntityType.PUBLICATION;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.orcid.service.OrcidSynchronizationService;
|
||||
import org.dspace.app.profile.OrcidEntitySyncPreference;
|
||||
import org.dspace.app.profile.OrcidProfileSyncPreference;
|
||||
import org.dspace.app.profile.OrcidSynchronizationMode;
|
||||
import org.dspace.app.profile.ResearcherProfile;
|
||||
import org.dspace.app.profile.service.ResearcherProfileService;
|
||||
import org.dspace.app.rest.exception.RESTAuthorizationException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implementation for ResearcherProfile ORCID synchronization preferences
|
||||
* patches.
|
||||
*
|
||||
* Example:
|
||||
* <code> curl -X PATCH http://${dspace.server.url}/api/cris/profiles/<:id-eperson> -H "
|
||||
* Content-Type: application/json" -d '[{
|
||||
* "op": "replace",
|
||||
* "path": "/orcid/publications",
|
||||
* "value": "ALL"
|
||||
* }]'
|
||||
* </code>
|
||||
*/
|
||||
@Component
|
||||
public class ResearcherProfileReplaceOrcidSyncPreferencesOperation extends PatchOperation<ResearcherProfile> {
|
||||
|
||||
private static final String OPERATION_ORCID_SYNCH = "/orcid";
|
||||
|
||||
private static final String PUBLICATIONS_PREFERENCES = "/publications";
|
||||
|
||||
private static final String FUNDINGS_PREFERENCES = "/fundings";
|
||||
|
||||
private static final String PROFILE_PREFERENCES = "/profile";
|
||||
|
||||
private static final String MODE_PREFERENCES = "/mode";
|
||||
|
||||
@Autowired
|
||||
private ResearcherProfileService profileService;
|
||||
|
||||
@Autowired
|
||||
private OrcidSynchronizationService synchronizationService;
|
||||
|
||||
@Override
|
||||
public ResearcherProfile perform(Context context, ResearcherProfile profile, Operation operation)
|
||||
throws SQLException {
|
||||
|
||||
String path = StringUtils.removeStart(operation.getPath(), OPERATION_ORCID_SYNCH);
|
||||
String value = getNewValueFromOperation(operation);
|
||||
|
||||
Item profileItem = profile.getItem();
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
try {
|
||||
updatePreferences(context, path, value, profileItem);
|
||||
|
||||
return profileService.findById(context, profile.getId());
|
||||
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RESTAuthorizationException(e);
|
||||
} finally {
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getNewValueFromOperation(Operation operation) {
|
||||
Object valueObject = operation.getValue();
|
||||
if (valueObject == null | !(valueObject instanceof String)) {
|
||||
throw new UnprocessableEntityException("The /orcid value must be a string");
|
||||
}
|
||||
return (String) valueObject;
|
||||
}
|
||||
|
||||
private boolean updatePreferences(Context context, String path, String value, Item profileItem)
|
||||
throws SQLException {
|
||||
switch (path) {
|
||||
case PUBLICATIONS_PREFERENCES:
|
||||
OrcidEntitySyncPreference preference = parsePreference(value);
|
||||
return synchronizationService.setEntityPreference(context, profileItem, PUBLICATION, preference);
|
||||
case FUNDINGS_PREFERENCES:
|
||||
OrcidEntitySyncPreference fundingPreference = parsePreference(value);
|
||||
return synchronizationService.setEntityPreference(context, profileItem, FUNDING, fundingPreference);
|
||||
case PROFILE_PREFERENCES:
|
||||
List<OrcidProfileSyncPreference> profilePreferences = parseProfilePreferences(value);
|
||||
return synchronizationService.setProfilePreference(context, profileItem, profilePreferences);
|
||||
case MODE_PREFERENCES:
|
||||
return synchronizationService.setSynchronizationMode(context, profileItem, parseMode(value));
|
||||
default:
|
||||
throw new UnprocessableEntityException("Invalid path starting with " + OPERATION_ORCID_SYNCH);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Object objectToMatch, Operation operation) {
|
||||
return objectToMatch instanceof ResearcherProfile
|
||||
&& operation.getOp().trim().equalsIgnoreCase(OPERATION_REPLACE)
|
||||
&& operation.getPath().trim().toLowerCase().startsWith(OPERATION_ORCID_SYNCH);
|
||||
}
|
||||
|
||||
private List<OrcidProfileSyncPreference> parseProfilePreferences(String value) {
|
||||
return Arrays.stream(value.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::isNotEmpty)
|
||||
.map(this::parseProfilePreference)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private OrcidProfileSyncPreference parseProfilePreference(String value) {
|
||||
try {
|
||||
return OrcidProfileSyncPreference.valueOf(value.toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new UnprocessableEntityException("Invalid profile's synchronization preference value: " + value, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private OrcidSynchronizationMode parseMode(String value) {
|
||||
try {
|
||||
return OrcidSynchronizationMode.valueOf(value.toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new UnprocessableEntityException("Invalid synchronization mode value: " + value, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private OrcidEntitySyncPreference parsePreference(String value) {
|
||||
try {
|
||||
return OrcidEntitySyncPreference.valueOf(value.toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new UnprocessableEntityException("Invalid synchronization preference value: " + value, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -11,14 +11,19 @@ import static com.jayway.jsonpath.JsonPath.read;
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.UUID.fromString;
|
||||
import static org.dspace.app.matcher.MetadataValueMatcher.with;
|
||||
import static org.dspace.app.profile.OrcidEntitySyncPreference.ALL;
|
||||
import static org.dspace.app.rest.matcher.HalMatcher.matchLinks;
|
||||
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
|
||||
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataDoesNotExist;
|
||||
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataNotEmpty;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
@@ -52,6 +57,7 @@ import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.util.UUIDUtils;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -1030,19 +1036,318 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneFromExternalProfileAlreadyAssociated() throws Exception {
|
||||
public void testOrcidMetadataOfEpersonAreCopiedOnProfile() throws Exception {
|
||||
|
||||
String id = user.getID().toString();
|
||||
String authToken = getAuthToken(user.getEmail(), password);
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/").contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated()).andExpect(jsonPath("$.id", is(id)))
|
||||
.andExpect(jsonPath("$.visible", is(false))).andExpect(jsonPath("$.type", is("profile")));
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withOrcid("0000-1111-2222-3333")
|
||||
.withEmail("test@email.it")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Test", "User")
|
||||
.withOrcidAccessToken("af097328-ac1c-4a3e-9eb4-069897874910")
|
||||
.withOrcidRefreshToken("32aadae0-829e-49c5-824f-ccaf4d1913e4")
|
||||
.withOrcidScope("/first-scope")
|
||||
.withOrcidScope("/second-scope")
|
||||
.build();
|
||||
|
||||
getClient(authToken)
|
||||
.perform(post("/api/eperson/profiles/").contentType(TEXT_URI_LIST)
|
||||
.content("http://localhost:8080/server/api/core/items/" + id))
|
||||
.andExpect(status().isConflict());
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String ePersonId = ePerson.getID().toString();
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.id", is(ePersonId.toString())))
|
||||
.andExpect(jsonPath("$.visible", is(false)))
|
||||
.andExpect(jsonPath("$.type", is("profile")));
|
||||
|
||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}", ePersonId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcid", is("0000-1111-2222-3333")))
|
||||
.andExpect(jsonPath("$.orcidSynchronization.mode", is("MANUAL")))
|
||||
.andExpect(jsonPath("$.orcidSynchronization.publicationsPreference", is("DISABLED")))
|
||||
.andExpect(jsonPath("$.orcidSynchronization.fundingsPreference", is("DISABLED")))
|
||||
.andExpect(jsonPath("$.orcidSynchronization.profilePreferences", empty()));
|
||||
|
||||
String itemId = getItemIdByProfileId(authToken, ePersonId);
|
||||
|
||||
Item profileItem = itemService.find(context, UUIDUtils.fromString(itemId));
|
||||
assertThat(profileItem, notNullValue());
|
||||
|
||||
List<MetadataValue> metadata = profileItem.getMetadata();
|
||||
assertThat(metadata, hasItem(with("person.identifier.orcid", "0000-1111-2222-3333")));
|
||||
assertThat(metadata, hasItem(with("dspace.orcid.access-token", "af097328-ac1c-4a3e-9eb4-069897874910")));
|
||||
assertThat(metadata, hasItem(with("dspace.orcid.refresh-token", "32aadae0-829e-49c5-824f-ccaf4d1913e4")));
|
||||
assertThat(metadata, hasItem(with("dspace.orcid.scope", "/first-scope", 0)));
|
||||
assertThat(metadata, hasItem(with("dspace.orcid.scope", "/second-scope", 1)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatchToSetOrcidSynchronizationPreferenceForPublications() throws Exception {
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withOrcid("0000-1111-2222-3333")
|
||||
.withEmail("test@email.it")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Test", "User")
|
||||
.withOrcidAccessToken("af097328-ac1c-4a3e-9eb4-069897874910")
|
||||
.withOrcidRefreshToken("32aadae0-829e-49c5-824f-ccaf4d1913e4")
|
||||
.withOrcidScope("/first-scope")
|
||||
.withOrcidScope("/second-scope")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String ePersonId = ePerson.getID().toString();
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
List<Operation> operations = asList(new ReplaceOperation("/orcid/publications", ALL.name()));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.publicationsPreference", is(ALL.name())));
|
||||
|
||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}", ePersonId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.publicationsPreference", is(ALL.name())));
|
||||
|
||||
operations = asList(new ReplaceOperation("/orcid/publications", "INVALID_VALUE"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatchToSetOrcidSynchronizationPreferenceForFundings() throws Exception {
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withOrcid("0000-1111-2222-3333")
|
||||
.withEmail("test@email.it")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Test", "User")
|
||||
.withOrcidAccessToken("af097328-ac1c-4a3e-9eb4-069897874910")
|
||||
.withOrcidRefreshToken("32aadae0-829e-49c5-824f-ccaf4d1913e4")
|
||||
.withOrcidScope("/first-scope")
|
||||
.withOrcidScope("/second-scope")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String ePersonId = ePerson.getID().toString();
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
List<Operation> operations = asList(new ReplaceOperation("/orcid/fundings", ALL.name()));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.fundingsPreference", is(ALL.name())));
|
||||
|
||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}", ePersonId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.fundingsPreference", is(ALL.name())));
|
||||
|
||||
operations = asList(new ReplaceOperation("/orcid/fundings", "INVALID_VALUE"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatchToSetOrcidSynchronizationPreferenceForProfile() throws Exception {
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withOrcid("0000-1111-2222-3333")
|
||||
.withEmail("test@email.it")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Test", "User")
|
||||
.withOrcidAccessToken("af097328-ac1c-4a3e-9eb4-069897874910")
|
||||
.withOrcidRefreshToken("32aadae0-829e-49c5-824f-ccaf4d1913e4")
|
||||
.withOrcidScope("/first-scope")
|
||||
.withOrcidScope("/second-scope")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String ePersonId = ePerson.getID().toString();
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
List<Operation> operations = asList(new ReplaceOperation("/orcid/profile", "IDENTIFIERS"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.profilePreferences",
|
||||
containsInAnyOrder("IDENTIFIERS")));
|
||||
|
||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}", ePersonId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.profilePreferences",
|
||||
containsInAnyOrder("IDENTIFIERS")));
|
||||
|
||||
operations = asList(new ReplaceOperation("/orcid/profiles", "INVALID_VALUE"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatchToSetOrcidSynchronizationMode() throws Exception {
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withOrcid("0000-1111-2222-3333")
|
||||
.withEmail("test@email.it")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Test", "User")
|
||||
.withOrcidAccessToken("af097328-ac1c-4a3e-9eb4-069897874910")
|
||||
.withOrcidRefreshToken("32aadae0-829e-49c5-824f-ccaf4d1913e4")
|
||||
.withOrcidScope("/first-scope")
|
||||
.withOrcidScope("/second-scope")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String ePersonId = ePerson.getID().toString();
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
List<Operation> operations = asList(new ReplaceOperation("/orcid/mode", "BATCH"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.mode", is("BATCH")));
|
||||
|
||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}", ePersonId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.mode", is("BATCH")));
|
||||
|
||||
operations = asList(new ReplaceOperation("/orcid/mode", "MANUAL"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.mode", is("MANUAL")));
|
||||
|
||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}", ePersonId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.orcidSynchronization.mode", is("MANUAL")));
|
||||
|
||||
operations = asList(new ReplaceOperation("/orcid/mode", "INVALID_VALUE"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatchToSetOrcidSynchronizationPreferenceWithWrongPath() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withOrcid("0000-1111-2222-3333")
|
||||
.withEmail("test@email.it")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Test", "User")
|
||||
.withOrcidAccessToken("af097328-ac1c-4a3e-9eb4-069897874910")
|
||||
.withOrcidRefreshToken("32aadae0-829e-49c5-824f-ccaf4d1913e4")
|
||||
.withOrcidScope("/first-scope")
|
||||
.withOrcidScope("/second-scope")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String ePersonId = ePerson.getID().toString();
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
List<Operation> operations = asList(new ReplaceOperation("/orcid/wrong-path", "BATCH"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatchToSetOrcidSynchronizationPreferenceWithProfileNotLinkedToOrcid() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||
.withCanLogin(true)
|
||||
.withOrcid("0000-1111-2222-3333")
|
||||
.withEmail("test@email.it")
|
||||
.withPassword(password)
|
||||
.withNameInMetadata("Test", "User")
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String ePersonId = ePerson.getID().toString();
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated());
|
||||
|
||||
List<Operation> operations = asList(new ReplaceOperation("/orcid/mode", "BATCH"));
|
||||
|
||||
getClient(authToken).perform(patch("/api/eperson/profiles/{id}", ePersonId)
|
||||
.content(getPatchContent(operations))
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1528,6 +1833,22 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
||||
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneFromExternalProfileAlreadyAssociated() throws Exception {
|
||||
|
||||
String id = user.getID().toString();
|
||||
String authToken = getAuthToken(user.getEmail(), password);
|
||||
|
||||
getClient(authToken).perform(post("/api/eperson/profiles/").contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(status().isCreated()).andExpect(jsonPath("$.id", is(id)))
|
||||
.andExpect(jsonPath("$.visible", is(false))).andExpect(jsonPath("$.type", is("profile")));
|
||||
|
||||
getClient(authToken)
|
||||
.perform(post("/api/eperson/profiles/").contentType(TEXT_URI_LIST)
|
||||
.content("http://localhost:8080/server/api/core/items/" + id))
|
||||
.andExpect(status().isConflict());
|
||||
}
|
||||
|
||||
private Item createProfile(EPerson ePerson) throws Exception {
|
||||
|
||||
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||
|
@@ -72,6 +72,34 @@
|
||||
<scope_note></scope_note>
|
||||
</dc-type>
|
||||
|
||||
<dc-type>
|
||||
<schema>dspace</schema>
|
||||
<element>orcid</element>
|
||||
<qualifier>sync-mode</qualifier>
|
||||
<scope_note></scope_note>
|
||||
</dc-type>
|
||||
|
||||
<dc-type>
|
||||
<schema>dspace</schema>
|
||||
<element>orcid</element>
|
||||
<qualifier>sync-publications</qualifier>
|
||||
<scope_note></scope_note>
|
||||
</dc-type>
|
||||
|
||||
<dc-type>
|
||||
<schema>dspace</schema>
|
||||
<element>orcid</element>
|
||||
<qualifier>sync-fundings</qualifier>
|
||||
<scope_note></scope_note>
|
||||
</dc-type>
|
||||
|
||||
<dc-type>
|
||||
<schema>dspace</schema>
|
||||
<element>orcid</element>
|
||||
<qualifier>sync-profile</qualifier>
|
||||
<scope_note></scope_note>
|
||||
</dc-type>
|
||||
|
||||
<dc-type>
|
||||
<schema>dspace</schema>
|
||||
<element>orcid</element>
|
||||
|
Reference in New Issue
Block a user