[CST-5587] Various improvements

This commit is contained in:
Luca Giamminonni
2022-06-20 13:55:35 +02:00
parent 258c9a1b4d
commit 18573ff054
63 changed files with 809 additions and 780 deletions

View File

@@ -32,11 +32,10 @@ import org.hibernate.annotations.Type;
* to synchronize the DSpace items and information on ORCID. While the entity
* {@link OrcidQueue} contains the data to be synchronized with ORCID, this
* entity instead contains the data synchronized with ORCID, with the result of
* the synchronization. Each record in this table is associated with an owner
* (the profile item) and the entity synchronized (which can be the profile
* itself, a publication or a project/funding). If the entity is the profile
* itself then the metadata field contains the signature of the information
* synchronized.
* the synchronization. Each record in this table is associated with a profile
* item and the entity synchronized (which can be the profile itself, a
* publication or a project/funding). If the entity is the profile itself then
* the metadata field contains the signature of the information synchronized.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
@@ -55,7 +54,7 @@ public class OrcidHistory implements ReloadableEntity<Integer> {
*/
@ManyToOne
@JoinColumn(name = "owner_id")
protected Item owner;
protected Item profileItem;
/**
* The synchronized item.
@@ -65,7 +64,8 @@ public class OrcidHistory implements ReloadableEntity<Integer> {
private Item entity;
/**
* The identifier of the synchronized resource on ORCID side.
* The identifier of the synchronized resource on ORCID side. For more details
* see https://info.orcid.org/faq/what-is-a-put-code/
*/
@Column(name = "put_code")
private String putCode;
@@ -136,12 +136,12 @@ public class OrcidHistory implements ReloadableEntity<Integer> {
return id;
}
public Item getOwner() {
return owner;
public Item getProfileItem() {
return profileItem;
}
public void setOwner(Item owner) {
this.owner = owner;
public void setProfileItem(Item profileItem) {
this.profileItem = profileItem;
}
public Item getEntity() {

View File

@@ -30,8 +30,8 @@ import org.hibernate.annotations.Type;
/**
* Entity that model a record on the ORCID synchronization queue. Each record in
* this table is associated with an owner (the profile item) and the entity to
* be synchronized (which can be the profile itself, a publication or a
* this table is associated with an profile item and the entity to be
* synchronized (which can be the profile itself, a publication or a
* project/funding). If the entity is the profile itself then the metadata field
* contains the signature of the information to be synchronized.
*
@@ -52,7 +52,7 @@ public class OrcidQueue implements ReloadableEntity<Integer> {
*/
@ManyToOne
@JoinColumn(name = "owner_id")
protected Item owner;
protected Item profileItem;
/**
* The entity to be synchronized.
@@ -69,7 +69,8 @@ public class OrcidQueue implements ReloadableEntity<Integer> {
/**
* The identifier of the resource to be synchronized on ORCID side (in case of
* update or deletion).
* update or deletion). For more details see
* https://info.orcid.org/faq/what-is-a-put-code/
*/
@Column(name = "put_code")
private String putCode;
@@ -123,12 +124,12 @@ public class OrcidQueue implements ReloadableEntity<Integer> {
return this.id;
}
public Item getOwner() {
return owner;
public Item getProfileItem() {
return profileItem;
}
public void setOwner(Item owner) {
this.owner = owner;
public void setProfileItem(Item profileItem) {
this.profileItem = profileItem;
}
public Item getEntity() {
@@ -209,7 +210,8 @@ public class OrcidQueue implements ReloadableEntity<Integer> {
@Override
public String toString() {
return "OrcidQueue [id=" + id + ", owner=" + owner + ", entity=" + entity + ", description=" + description
return "OrcidQueue [id=" + id + ", profileItem=" + profileItem + ", entity=" + entity + ", description="
+ description
+ ", putCode=" + putCode + ", recordType=" + recordType + ", metadata=" + metadata + ", operation="
+ operation + "]";
}

View File

@@ -128,8 +128,7 @@ public class OrcidClientImpl implements OrcidClient {
@Override
public OrcidResponse deleteByPutCode(String accessToken, String orcid, String putCode, String path) {
String apiUrl = orcidConfiguration.getApiUrl();
return execute(buildDeleteUriRequest(accessToken, apiUrl, "/" + orcid + path + "/" + putCode), true);
return execute(buildDeleteUriRequest(accessToken, "/" + orcid + path + "/" + putCode), true);
}
private HttpUriRequest buildGetUriRequest(String accessToken, String relativePath) {
@@ -155,8 +154,8 @@ public class OrcidClientImpl implements OrcidClient {
.build();
}
private HttpUriRequest buildDeleteUriRequest(String accessToken, String baseUrl, String relativePath) {
return delete(baseUrl + relativePath.trim())
private HttpUriRequest buildDeleteUriRequest(String accessToken, String relativePath) {
return delete(orcidConfiguration.getApiUrl() + relativePath.trim())
.addHeader("Authorization", "Bearer " + accessToken)
.build();
}
@@ -179,6 +178,17 @@ public class OrcidClientImpl implements OrcidClient {
}
/**
* Execute the given httpUriRequest, unmarshalling the content with the given
* class.
* @param httpUriRequest the http request to be executed
* @param handleNotFoundAsNull if true this method returns null if the response
* status is 404, if false throws an
* OrcidClientException
* @param clazz the class to be used for the content unmarshall
* @return the response body
* @throws OrcidClientException if the incoming response is not successfull
*/
private <T> T executeAndUnmarshall(HttpUriRequest httpUriRequest, boolean handleNotFoundAsNull, Class<T> clazz) {
HttpClient client = HttpClientBuilder.create().build();
@@ -291,6 +301,13 @@ public class OrcidClientImpl implements OrcidClient {
return entity != null ? IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8.name()) : null;
}
/**
* Returns the put code present in the given http response, if any. For more
* details about the put code see For more details see
* https://info.orcid.org/faq/what-is-a-put-code/
* @param response the http response coming from ORCID
* @return the put code, if any
*/
private String getPutCode(HttpResponse response) {
Header[] headers = response.getHeaders("Location");
if (headers.length == 0) {

View File

@@ -102,10 +102,16 @@ public class OrcidQueueConsumer implements Consumer {
@Override
public void consume(Context context, Event event) throws Exception {
if (isOrcidSynchronizationDisabled()) {
return;
}
DSpaceObject dso = event.getSubject(context);
if (!(dso instanceof Item)) {
return;
}
Item item = (Item) dso;
if (!item.isArchived()) {
return;
@@ -115,16 +121,13 @@ public class OrcidQueueConsumer implements Consumer {
return;
}
if (isOrcidSynchronizationDisabled()) {
return;
}
context.turnOffAuthorisationSystem();
try {
consumeItem(context, item);
} finally {
context.restoreAuthSystemState();
}
}
/**
@@ -198,7 +201,7 @@ public class OrcidQueueConsumer implements Consumer {
orcidQueueService.deleteByEntityAndRecordType(context, item, sectionType);
if (isSynchronizationDisabled(context, item, factory)) {
if (isProfileSectionSynchronizationDisabled(context, item, factory)) {
continue;
}
@@ -212,7 +215,8 @@ public class OrcidQueueConsumer implements Consumer {
}
private boolean isSynchronizationDisabled(Context context, Item item, OrcidProfileSectionFactory factory) {
private boolean isProfileSectionSynchronizationDisabled(Context context,
Item item, OrcidProfileSectionFactory factory) {
List<OrcidProfileSyncPreference> preferences = this.orcidSynchronizationService.getProfilePreferences(item);
return !preferences.contains(factory.getSynchronizationPreference());
}
@@ -304,25 +308,25 @@ public class OrcidQueueConsumer implements Consumer {
.findFirst();
}
private boolean isAlreadyQueued(Context context, Item owner, Item entity) throws SQLException {
return isNotEmpty(orcidQueueService.findByOwnerAndEntity(context, owner, entity));
private boolean isAlreadyQueued(Context context, Item profileItem, Item entity) throws SQLException {
return isNotEmpty(orcidQueueService.findByProfileItemAndEntity(context, profileItem, entity));
}
private boolean isNotLinkedToOrcid(Context context, Item ownerItem) {
return hasNotOrcidAccessToken(context, ownerItem)
|| getMetadataValue(ownerItem, "person.identifier.orcid") == null;
private boolean isNotLinkedToOrcid(Context context, Item profileItemItem) {
return hasNotOrcidAccessToken(context, profileItemItem)
|| getMetadataValue(profileItemItem, "person.identifier.orcid") == null;
}
private boolean hasNotOrcidAccessToken(Context context, Item ownerItem) {
return orcidTokenService.findByProfileItem(context, ownerItem) == null;
private boolean hasNotOrcidAccessToken(Context context, Item profileItemItem) {
return orcidTokenService.findByProfileItem(context, profileItemItem) == null;
}
private boolean shouldNotBeSynchronized(Item owner, Item entity) {
return !orcidSynchronizationService.isSynchronizationEnabled(owner, entity);
private boolean shouldNotBeSynchronized(Item profileItem, Item entity) {
return !orcidSynchronizationService.isSynchronizationAllowed(profileItem, entity);
}
private boolean isNotProfileItem(Item ownerItem) {
return !getProfileType().equals(itemService.getEntityTypeLabel(ownerItem));
private boolean isNotProfileItem(Item profileItemItem) {
return !getProfileType().equals(itemService.getEntityTypeLabel(profileItemItem));
}
private String getMetadataValue(Item item, String metadataField) {

View File

@@ -28,25 +28,27 @@ import org.dspace.core.GenericDAO;
public interface OrcidHistoryDAO extends GenericDAO<OrcidHistory> {
/**
* Find all the ORCID history records by the given owner and entity uuids.
* Find all the ORCID history records by the given profileItem and entity uuids.
*
* @param context the DSpace context
* @param ownerId the owner item uuid
* @param entityId the entity item uuid
* @return the records list
* @throws SQLException if an SQL error occurs
* @param context the DSpace context
* @param profileItemId the profileItem item uuid
* @param entityId the entity item uuid
* @return the records list
* @throws SQLException if an SQL error occurs
*/
List<OrcidHistory> findByOwnerAndEntity(Context context, UUID ownerId, UUID entityId) throws SQLException;
List<OrcidHistory> findByProfileItemAndEntity(Context context, UUID profileItemId, UUID entityId)
throws SQLException;
/**
* Get the OrcidHistory records where the given item is the owner or the entity
* Get the OrcidHistory records where the given item is the profileItem or the
* entity
*
* @param context DSpace context object
* @param item the item to search for
* @return the found OrcidHistory entities
* @throws SQLException if database error
*/
public List<OrcidHistory> findByOwnerOrEntity(Context context, Item item) throws SQLException;
public List<OrcidHistory> findByProfileItemOrEntity(Context context, Item item) throws SQLException;
/**
* Find the OrcidHistory records related to the given entity item.

View File

@@ -28,48 +28,51 @@ import org.dspace.core.GenericDAO;
public interface OrcidQueueDAO extends GenericDAO<OrcidQueue> {
/**
* Get the orcid queue records by the owner id.
* Get the orcid queue records by the profileItem id.
*
* @param context DSpace context object
* @param ownerId the owner item id
* @param limit limit
* @param offset offset
* @return the orcid queue records
* @throws SQLException if an SQL error occurs
* @param context DSpace context object
* @param profileItemId the profileItem item id
* @param limit limit
* @param offset offset
* @return the orcid queue records
* @throws SQLException if an SQL error occurs
*/
public List<OrcidQueue> findByOwnerId(Context context, UUID ownerId, Integer limit, Integer offset)
public List<OrcidQueue> findByProfileItemId(Context context, UUID profileItemId, Integer limit, Integer offset)
throws SQLException;
/**
* Count the orcid queue records with the same ownerId.
* Count the orcid queue records with the same profileItemId.
*
* @param context DSpace context object
* @param ownerId the owner item id
* @return the count result
* @throws SQLException if an SQL error occurs
* @param context DSpace context object
* @param profileItemId the profileItem item id
* @return the count result
* @throws SQLException if an SQL error occurs
*/
long countByOwnerId(Context context, UUID ownerId) throws SQLException;
long countByProfileItemId(Context context, UUID profileItemId) throws SQLException;
/**
* Returns all the orcid queue records with the given owner and entity items.
* Returns all the orcid queue records with the given profileItem and entity
* items.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param entity the entity item
* @return the found orcid queue records
* @throws SQLException
*/
public List<OrcidQueue> findByOwnerAndEntity(Context context, Item owner, Item entity) throws SQLException;
public List<OrcidQueue> findByProfileItemAndEntity(Context context, Item profileItem, Item entity)
throws SQLException;
/**
* Get the OrcidQueue records where the given item is the owner OR the entity
* Get the OrcidQueue records where the given item is the profileItem OR the
* entity
*
* @param context DSpace context object
* @param item the item to search for
* @return the found OrcidHistory entities
* @throws SQLException if database error
*/
public List<OrcidQueue> findByOwnerOrEntity(Context context, Item item) throws SQLException;
public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) throws SQLException;
/**
* Find all the OrcidQueue records with the given entity and record type.
@@ -82,14 +85,15 @@ public interface OrcidQueueDAO extends GenericDAO<OrcidQueue> {
public List<OrcidQueue> findByEntityAndRecordType(Context context, Item entity, String type) throws SQLException;
/**
* Find all the OrcidQueue records with the given owner and record type.
* Find all the OrcidQueue records with the given profileItem and record type.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param type the record type
* @throws SQLException if database error occurs
*/
public List<OrcidQueue> findByOwnerAndRecordType(Context context, Item owner, String type) throws SQLException;
public List<OrcidQueue> findByProfileItemAndRecordType(Context context, Item profileItem, String type)
throws SQLException;
/**
* Get all the OrcidQueue records with attempts less than the given attempts.

View File

@@ -28,16 +28,18 @@ import org.dspace.core.Context;
public class OrcidHistoryDAOImpl extends AbstractHibernateDAO<OrcidHistory> implements OrcidHistoryDAO {
@Override
public List<OrcidHistory> findByOwnerAndEntity(Context context, UUID ownerId, UUID entityId) throws SQLException {
Query query = createQuery(context, "FROM OrcidHistory WHERE owner.id = :ownerId AND entity.id = :entityId ");
query.setParameter("ownerId", ownerId);
public List<OrcidHistory> findByProfileItemAndEntity(Context context, UUID profileItemId, UUID entityId)
throws SQLException {
Query query = createQuery(context,
"FROM OrcidHistory WHERE profileItem.id = :profileItemId AND entity.id = :entityId ");
query.setParameter("profileItemId", profileItemId);
query.setParameter("entityId", entityId);
return query.getResultList();
}
@Override
public List<OrcidHistory> findByOwnerOrEntity(Context context, Item item) throws SQLException {
Query query = createQuery(context, "FROM OrcidHistory WHERE owner.id = :itemId OR entity.id = :itemId");
public List<OrcidHistory> findByProfileItemOrEntity(Context context, Item item) throws SQLException {
Query query = createQuery(context, "FROM OrcidHistory WHERE profileItem.id = :itemId OR entity.id = :itemId");
query.setParameter("itemId", item.getID());
return query.getResultList();
}

View File

@@ -28,10 +28,10 @@ import org.dspace.core.Context;
public class OrcidQueueDAOImpl extends AbstractHibernateDAO<OrcidQueue> implements OrcidQueueDAO {
@Override
public List<OrcidQueue> findByOwnerId(Context context, UUID ownerId, Integer limit, Integer offset)
public List<OrcidQueue> findByProfileItemId(Context context, UUID profileItemId, Integer limit, Integer offset)
throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE owner.id= :ownerId");
query.setParameter("ownerId", ownerId);
Query query = createQuery(context, "FROM OrcidQueue WHERE profileItem.id= :profileItemId");
query.setParameter("profileItemId", profileItemId);
if (limit != null && limit.intValue() > 0) {
query.setMaxResults(limit);
}
@@ -40,23 +40,25 @@ public class OrcidQueueDAOImpl extends AbstractHibernateDAO<OrcidQueue> implemen
}
@Override
public List<OrcidQueue> findByOwnerAndEntity(Context context, Item owner, Item entity) throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE owner = :owner AND entity = :entity");
query.setParameter("owner", owner);
public List<OrcidQueue> findByProfileItemAndEntity(Context context, Item profileItem, Item entity)
throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE profileItem = :profileItem AND entity = :entity");
query.setParameter("profileItem", profileItem);
query.setParameter("entity", entity);
return query.getResultList();
}
@Override
public long countByOwnerId(Context context, UUID ownerId) throws SQLException {
Query query = createQuery(context, "SELECT COUNT(queue) FROM OrcidQueue queue WHERE owner.id= :ownerId");
query.setParameter("ownerId", ownerId);
public long countByProfileItemId(Context context, UUID profileItemId) throws SQLException {
Query query = createQuery(context,
"SELECT COUNT(queue) FROM OrcidQueue queue WHERE profileItem.id= :profileItemId");
query.setParameter("profileItemId", profileItemId);
return (long) query.getSingleResult();
}
@Override
public List<OrcidQueue> findByOwnerOrEntity(Context context, Item item) throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE owner.id= :itemId OR entity.id = :itemId");
public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE profileItem.id= :itemId OR entity.id = :itemId");
query.setParameter("itemId", item.getID());
return query.getResultList();
}
@@ -70,9 +72,10 @@ public class OrcidQueueDAOImpl extends AbstractHibernateDAO<OrcidQueue> implemen
}
@Override
public List<OrcidQueue> findByOwnerAndRecordType(Context context, Item owner, String type) throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE owner = :owner AND recordType = :type");
query.setParameter("owner", owner);
public List<OrcidQueue> findByProfileItemAndRecordType(Context context, Item profileItem, String type)
throws SQLException {
Query query = createQuery(context, "FROM OrcidQueue WHERE profileItem = :profileItem AND recordType = :type");
query.setParameter("profileItem", profileItem);
query.setParameter("type", type);
return query.getResultList();
}

View File

@@ -11,6 +11,8 @@ import org.apache.commons.lang3.EnumUtils;
/**
* Enum that model all the ORCID profile sections that could be synchronized.
* These fields come from the ORCID PERSON schema, see
* https://info.orcid.org/documentation/integration-guide/orcid-record/#PERSON
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*

View File

@@ -19,10 +19,11 @@ import java.util.stream.Collectors;
import org.dspace.util.SimpleMapConverter;
import org.orcid.jaxb.model.common.ContributorRole;
import org.orcid.jaxb.model.v3.release.record.Work;
/**
* Class that contains all the mapping between {@link Work} and DSpaceCris
* metadata fields.
* Class that contains all the mapping between {@link Work} and DSpace metadata
* fields.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*

View File

@@ -13,7 +13,9 @@ import java.util.Map;
import org.apache.commons.lang3.StringUtils;
/**
* Utility class for Orcid factory classes.
* Utility class for Orcid factory classes. This is used to parse the
* configuration of ORCID entities defined in orcid.cfg (for example see
* contributors and external ids configuration).
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
@@ -26,7 +28,8 @@ public final class OrcidFactoryUtils {
/**
* Parse the given configurations value and returns a map with metadata fields
* as keys and types/sources as values.
* as keys and types/sources as values. The expected configuration syntax is a
* list of values field::type separated by commas.
*
* @param configurations the configurations to parse
* @return the configurations parsing result as map

View File

@@ -257,10 +257,6 @@ public class OrcidCommonObjectFactoryImpl implements OrcidCommonObjectFactory {
return contributorOrcidField;
}
public ItemService getItemService() {
return itemService;
}
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}

View File

@@ -146,13 +146,19 @@ public class OrcidFundingFactory implements OrcidEntityFactory {
return externalID;
}
/**
* Returns an Organization ORCID entity related to the given item. The
* relationship type configured with
* orcid.mapping.funding.organization-relationship-type is the relationship used
* to search the Organization of the given project item.
*/
private Organization getOrganization(Context context, Item item) {
try {
return relationshipTypeService.findByLeftwardOrRightwardTypeName(context,
fieldMapping.getOrganizationRelationshipType()).stream()
.flatMap(relationshipType -> getRelationship(context, item, relationshipType))
.flatMap(relationshipType -> getRelationships(context, item, relationshipType))
.map(relationship -> getRelatedItem(item, relationship))
.flatMap(orgUnit -> orcidCommonObjectFactory.createOrganization(context, orgUnit).stream())
.findFirst()
@@ -164,7 +170,7 @@ public class OrcidFundingFactory implements OrcidEntityFactory {
}
private Stream<Relationship> getRelationship(Context context, Item item, RelationshipType relationshipType) {
private Stream<Relationship> getRelationships(Context context, Item item, RelationshipType relationshipType) {
try {
return relationshipService.findByItemAndRelationshipType(context, item, relationshipType).stream();
} catch (SQLException e) {
@@ -194,6 +200,11 @@ public class OrcidFundingFactory implements OrcidEntityFactory {
return fundingTitle;
}
/**
* Returns an instance of FundingType taking the type from the given item. The
* metadata field to be used to retrieve the item's type is related to the
* configured typeField (orcid.mapping.funding.type).
*/
private FundingType getType(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getTypeField())
.map(type -> fieldMapping.convertType(type.getValue()))
@@ -214,17 +225,40 @@ public class OrcidFundingFactory implements OrcidEntityFactory {
return orcidCommonObjectFactory.createUrl(context, item).orElse(null);
}
/**
* Returns an Amount instance taking the amount and currency value from the
* configured metadata values of the given item, if any.
*/
private Amount getAmount(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getAmountField())
.flatMap(amount -> getAmount(context, item, amount.getValue()))
.orElse(null);
Optional<String> amount = getAmountValue(context, item);
Optional<String> currency = getCurrencyValue(context, item);
if (amount.isEmpty() || currency.isEmpty()) {
return null;
}
return getAmount(amount.get(), currency.get());
}
private Optional<Amount> getAmount(Context context, Item item, String amount) {
/**
* Returns the amount value of the configured metadata field
* orcid.mapping.funding.amount
*/
private Optional<String> getAmountValue(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getAmountField())
.map(MetadataValue::getValue);
}
/**
* Returns the amount value of the configured metadata field
* orcid.mapping.funding.amount.currency (if configured using the converter
* orcid.mapping.funding.amount.currency.converter).
*/
private Optional<String> getCurrencyValue(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getAmountCurrencyField())
.map(currency -> fieldMapping.convertAmountCurrency(currency.getValue()))
.filter(currency -> isValidCurrency(currency))
.map(currency -> getAmount(amount, currency));
.filter(currency -> isValidCurrency(currency));
}
private boolean isValidCurrency(String currency) {

View File

@@ -86,6 +86,10 @@ public class OrcidSimpleValueObjectFactory extends AbstractOrcidProfileSectionFa
return CollectionUtils.isNotEmpty(metadataValues) ? metadataValues.get(0).getValue() : null;
}
/**
* Create an instance of ORCID profile section based on the configured profile
* section type, taking the value from the given metadataValue.
*/
protected Object create(Context context, MetadataValue metadataValue) {
switch (getProfileSectionType()) {
case COUNTRY:

View File

@@ -107,24 +107,38 @@ public class OrcidWorkFactory implements OrcidEntityFactory {
return orcidCommonObjectFactory.createContributor(context, metadataValue, role);
}
/**
* Create an instance of WorkTitle from the given item.
*/
private WorkTitle getWorkTitle(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getTitleField())
.map(metadataValue -> getWorkTitle(context, item, metadataValue))
.orElse(null);
}
Optional<String> workTitleValue = getWorkTitleValue(context, item);
if (workTitleValue.isEmpty()) {
return null;
}
private WorkTitle getWorkTitle(Context context, Item item, MetadataValue metadataValue) {
WorkTitle workTitle = new WorkTitle();
workTitle.setTitle(new Title(metadataValue.getValue()));
workTitle.setSubtitle(getSubTitle(context, item));
workTitle.setTitle(new Title(workTitleValue.get()));
getSubTitle(context, item).ifPresent(workTitle::setSubtitle);
return workTitle;
}
private Subtitle getSubTitle(Context context, Item item) {
/**
* Take the work title from the configured metadata field of the given item
* (orcid.mapping.work.title), if any.
*/
private Optional<String> getWorkTitleValue(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getTitleField())
.map(MetadataValue::getValue);
}
/**
* Take the work title from the configured metadata field of the given item
* (orcid.mapping.work.sub-title), if any.
*/
private Optional<Subtitle> getSubTitle(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getSubTitleField())
.map(MetadataValue::getValue)
.map(Subtitle::new)
.orElse(null);
.map(Subtitle::new);
}
private PublicationDate getPublicationDate(Context context, Item item) {
@@ -134,12 +148,20 @@ public class OrcidWorkFactory implements OrcidEntityFactory {
.orElse(null);
}
/**
* Creates an instance of ExternalIDs from the metadata values of the given
* item, using the orcid.mapping.funding.external-ids configuration.
*/
private ExternalIDs getWorkExternalIds(Context context, Item item) {
ExternalIDs externalIdentifiers = new ExternalIDs();
externalIdentifiers.getExternalIdentifier().addAll(getWorkSelfExternalIds(context, item));
return externalIdentifiers;
}
/**
* Creates a list of ExternalID, one for orcid.mapping.funding.external-ids
* value, taking the values from the given item.
*/
private List<ExternalID> getWorkSelfExternalIds(Context context, Item item) {
List<ExternalID> selfExternalIds = new ArrayList<ExternalID>();
@@ -158,12 +180,22 @@ public class OrcidWorkFactory implements OrcidEntityFactory {
return selfExternalIds;
}
/**
* Creates an instance of ExternalID taking the value from the given
* metadataValue. The type of the ExternalID is calculated using the
* orcid.mapping.funding.external-ids configuration. The relationship of the
* ExternalID is SELF.
*/
private ExternalID getSelfExternalId(MetadataValue metadataValue) {
Map<String, String> externalIdentifierFields = fieldMapping.getExternalIdentifierFields();
String metadataField = metadataValue.getMetadataField().toString('.');
return getExternalId(externalIdentifierFields.get(metadataField), metadataValue.getValue(), SELF);
}
/**
* Creates an instance of ExternalID with the given type, value and
* relationship.
*/
private ExternalID getExternalId(String type, String value, Relationship relationship) {
ExternalID externalID = new ExternalID();
externalID.setType(type);
@@ -172,6 +204,10 @@ public class OrcidWorkFactory implements OrcidEntityFactory {
return externalID;
}
/**
* Creates an instance of WorkType from the given item, taking the value fom the
* configured metadata field (orcid.mapping.work.type).
*/
private WorkType getWorkType(Context context, Item item) {
return getMetadataValue(context, item, fieldMapping.getTypeField())
.map(MetadataValue::getValue)
@@ -180,6 +216,9 @@ public class OrcidWorkFactory implements OrcidEntityFactory {
.orElse(null);
}
/**
* Creates an instance of WorkType from the given workType value, if valid.
*/
private Optional<WorkType> getWorkType(String workType) {
try {
return Optional.ofNullable(WorkType.fromValue(workType));

View File

@@ -9,7 +9,11 @@ package org.dspace.app.orcid.model.validator;
/**
* Enum that model all the errors that could occurs during an ORCID object
* validation.
* validation. These codes are used by the {@link OrcidValidator} to returns the
* validation error related to a specific ORCID entity. The values of this enum
* are returned from the OrcidHistoryRestRepository and can be used to show an
* error message to the users when they tries to synchronize some data with
* ORCID.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
@@ -23,6 +27,7 @@ public enum OrcidValidationError {
FUNDER_REQUIRED("funder.required"),
INVALID_COUNTRY("country.invalid"),
ORGANIZATION_NAME_REQUIRED("organization.name-required"),
PUBLICATION_DATE_INVALID("publication.date-invalid"),
ORGANIZATION_ADDRESS_REQUIRED("organization.address-required"),
ORGANIZATION_CITY_REQUIRED("organization.city-required"),
ORGANIZATION_COUNTRY_REQUIRED("organization.country-required"),

View File

@@ -21,6 +21,7 @@ import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZA
import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZATION_CITY_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZATION_COUNTRY_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZATION_NAME_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.PUBLICATION_DATE_INVALID;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.TITLE_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.TYPE_REQUIRED;
@@ -34,6 +35,8 @@ import org.dspace.services.ConfigurationService;
import org.orcid.jaxb.model.v3.release.common.DisambiguatedOrganization;
import org.orcid.jaxb.model.v3.release.common.Organization;
import org.orcid.jaxb.model.v3.release.common.OrganizationAddress;
import org.orcid.jaxb.model.v3.release.common.PublicationDate;
import org.orcid.jaxb.model.v3.release.common.Year;
import org.orcid.jaxb.model.v3.release.record.ExternalIDs;
import org.orcid.jaxb.model.v3.release.record.Funding;
import org.orcid.jaxb.model.v3.release.record.FundingTitle;
@@ -68,6 +71,10 @@ public class OrcidValidatorImpl implements OrcidValidator {
return Collections.emptyList();
}
/**
* A work is valid if has title, type, a valid publication date and at least one
* external id.
*/
@Override
public List<OrcidValidationError> validateWork(Work work) {
List<OrcidValidationError> errors = new ArrayList<OrcidValidationError>();
@@ -87,9 +94,18 @@ public class OrcidValidatorImpl implements OrcidValidator {
errors.add(EXTERNAL_ID_REQUIRED);
}
PublicationDate publicationDate = work.getPublicationDate();
if (publicationDate != null && isYearNotValid(publicationDate)) {
errors.add(PUBLICATION_DATE_INVALID);
}
return errors;
}
/**
* A funding is valid if has title, a valid funder organization and at least one
* external id. If it has an amount, the amount currency is required.
*/
@Override
public List<OrcidValidationError> validateFunding(Funding funding) {
@@ -119,6 +135,10 @@ public class OrcidValidatorImpl implements OrcidValidator {
return errors;
}
/**
* The organization is valid if it has a name, a valid address and a valid
* disambiguated-organization complex type.
*/
private List<OrcidValidationError> validate(Organization organization) {
List<OrcidValidationError> errors = new ArrayList<OrcidValidationError>();
if (isBlank(organization.getName())) {
@@ -131,6 +151,11 @@ public class OrcidValidatorImpl implements OrcidValidator {
return errors;
}
/**
* A disambiguated-organization type is valid if it has an identifier and a
* valid source (the valid values for sources are configured with
* orcid.validation.organization.identifier-sources)
*/
private List<OrcidValidationError> validate(DisambiguatedOrganization disambiguatedOrganization) {
List<OrcidValidationError> errors = new ArrayList<OrcidValidationError>();
@@ -156,6 +181,9 @@ public class OrcidValidatorImpl implements OrcidValidator {
return errors;
}
/**
* An organization address is valid if it has a city and a country.
*/
private List<OrcidValidationError> validate(OrganizationAddress address) {
List<OrcidValidationError> errors = new ArrayList<OrcidValidationError>();
@@ -175,6 +203,19 @@ public class OrcidValidatorImpl implements OrcidValidator {
return errors;
}
private boolean isYearNotValid(PublicationDate publicationDate) {
Year year = publicationDate.getYear();
if (year == null) {
return true;
}
try {
return Integer.valueOf(year.getValue()) < 1900;
} catch (NumberFormatException ex) {
return true;
}
}
private boolean isInvalidDisambiguationSource(String disambiguationSource) {
return !contains(getDisambiguedOrganizationSources(), disambiguationSource);
}

View File

@@ -41,8 +41,8 @@ import org.slf4j.LoggerFactory;
/**
* Script that perform the bulk synchronization with ORCID registry of all the
* ORCID queue records that has an owner that configure the synchronization mode
* equals to BATCH.
* ORCID queue records that has an profileItem that configure the
* synchronization mode equals to BATCH.
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
@@ -60,7 +60,10 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
private Context context;
private Map<Item, OrcidSynchronizationMode> synchronizationModeByOwner = new HashMap<>();
/**
* Cache that stores the synchronization mode set for a specific profile item.
*/
private Map<Item, OrcidSynchronizationMode> synchronizationModeByProfileItem = new HashMap<>();
private boolean ignoreMaxAttempts = false;
@@ -80,6 +83,12 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
@Override
public void internalRun() throws Exception {
if (isOrcidSynchronizationDisabled()) {
handler.logWarning("The ORCID synchronization is disabled. The script cannot proceed");
return;
}
context = new Context();
assignCurrentUserInContext();
@@ -95,6 +104,10 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
}
}
/**
* Find all the Orcid Queue records that need to be synchronized and perfom the
* synchronization.
*/
private void performBulkSynchronization() throws SQLException {
List<OrcidQueue> queueRecords = findQueueRecordsToSynchronize();
@@ -106,12 +119,22 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
}
/**
* Returns all the stored Orcid Queue records (ignoring or not the max attempts)
* related to a profile that has the synchronization mode set to BATCH.
*/
private List<OrcidQueue> findQueueRecordsToSynchronize() throws SQLException {
return findQueueRecords().stream()
.filter(record -> getOwnerSynchronizationMode(record.getOwner()) == BATCH)
.filter(record -> getProfileItemSynchronizationMode(record.getProfileItem()) == BATCH)
.collect(Collectors.toList());
}
/**
* If the current script execution is configued to ignore the max attemps,
* returns all the ORCID Queue records, otherwise returns the ORCID Queue
* records that has an attempts value less than the configured max attempts
* value.
*/
private List<OrcidQueue> findQueueRecords() throws SQLException {
if (ignoreMaxAttempts) {
return orcidQueueService.findAll(context);
@@ -121,6 +144,9 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
}
}
/**
* Try to synchronize the given queue record with ORCID, handling any errors.
*/
private void performSynchronization(OrcidQueue queueRecord) {
try {
@@ -149,38 +175,49 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
}
private OrcidSynchronizationMode getOwnerSynchronizationMode(Item owner) {
OrcidSynchronizationMode synchronizationMode = synchronizationModeByOwner.get(owner);
/**
* Returns the Synchronization mode related to the given profile item.
*/
private OrcidSynchronizationMode getProfileItemSynchronizationMode(Item profileItem) {
OrcidSynchronizationMode synchronizationMode = synchronizationModeByProfileItem.get(profileItem);
if (synchronizationMode == null) {
synchronizationMode = orcidSynchronizationService.getSynchronizationMode(owner).orElse(MANUAL);
synchronizationModeByOwner.put(owner, synchronizationMode);
synchronizationMode = orcidSynchronizationService.getSynchronizationMode(profileItem).orElse(MANUAL);
synchronizationModeByProfileItem.put(profileItem, synchronizationMode);
}
return synchronizationMode;
}
/**
* Returns an info log message with the details of the given record's operation.
* This message is logged before ORCID synchronization.
*/
private String getOperationInfoMessage(OrcidQueue record) {
UUID ownerId = record.getOwner().getID();
UUID profileItemId = record.getProfileItem().getID();
String putCode = record.getPutCode();
String type = record.getRecordType();
if (record.getOperation() == null) {
return "Synchronization of " + type + " data for profile with ID: " + ownerId;
return "Synchronization of " + type + " data for profile with ID: " + profileItemId;
}
switch (record.getOperation()) {
case INSERT:
return "Addition of " + type + " for profile with ID: " + ownerId;
return "Addition of " + type + " for profile with ID: " + profileItemId;
case UPDATE:
return "Update of " + type + " for profile with ID: " + ownerId + " by put code " + putCode;
return "Update of " + type + " for profile with ID: " + profileItemId + " by put code " + putCode;
case DELETE:
return "Deletion of " + type + " for profile with ID: " + ownerId + " by put code " + putCode;
return "Deletion of " + type + " for profile with ID: " + profileItemId + " by put code " + putCode;
default:
return "Synchronization of " + type + " data for profile with ID: " + ownerId;
return "Synchronization of " + type + " data for profile with ID: " + profileItemId;
}
}
/**
* Returns an info log message with the details of the synchronization result.
* This message is logged after ORCID synchronization.
*/
private String getSynchronizationResultMessage(OrcidHistory orcidHistory) {
String message = "History record created with status " + orcidHistory.getStatus();
@@ -200,6 +237,9 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
case 409:
message += ". The resource is already present on the ORCID registry";
break;
case 500:
message += ". An internal server error on ORCID registry side occurs";
break;
default:
break;
}
@@ -232,6 +272,13 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
}
/**
* This method will assign the currentUser to the {@link Context}. The instance
* of the method in this class will fetch the EPersonIdentifier from this class,
* this identifier was given to this class upon instantiation, it'll then be
* used to find the {@link EPerson} associated with it and this {@link EPerson}
* will be set as the currentUser of the created {@link Context}
*/
private void assignCurrentUserInContext() throws SQLException {
UUID uuid = getEpersonIdentifier();
if (uuid != null) {
@@ -269,6 +316,10 @@ public class OrcidBulkPush extends DSpaceRunnable<OrcidBulkPushScriptConfigurati
return isNotEmpty(message) ? message.substring(message.indexOf(":") + 1).trim() : "Generic error";
}
private boolean isOrcidSynchronizationDisabled() {
return !configurationService.getBooleanProperty("orcid.synchronization-enabled", true);
}
@Override
@SuppressWarnings("unchecked")
public OrcidBulkPushScriptConfiguration<OrcidBulkPush> getScriptConfiguration() {

View File

@@ -15,7 +15,11 @@ import org.dspace.core.Context;
/**
* Interface that mark classes that can be used to generate a signature for
* metadata values.
* metadata values. The signature must be a unique identification of a metadata,
* based on the attributes that compose it (such as field, value and authority).
* It is possible to generate a signature for a single metadata value and also
* for a list of values. Given an item, a signature can for example be used to
* check if the associated metadata is present in the item.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*

View File

@@ -46,14 +46,15 @@ public interface OrcidHistoryService {
public List<OrcidHistory> findAll(Context context) throws SQLException;
/**
* Get the OrcidHistory records where the given item is the owner OR the entity
* Get the OrcidHistory records where the given item is the profile item OR the
* entity
*
* @param context DSpace context object
* @param item the item to search for
* @return the found OrcidHistory entities
* @throws SQLException if database error
*/
public List<OrcidHistory> findByOwnerOrEntity(Context context, Item item) throws SQLException;
public List<OrcidHistory> findByProfileItemOrEntity(Context context, Item item) throws SQLException;
/**
* Find the OrcidHistory records related to the given entity item.
@@ -66,16 +67,16 @@ public interface OrcidHistoryService {
public List<OrcidHistory> findByEntity(Context context, Item entity) throws SQLException;
/**
* Create a new OrcidHistory records related to the given owner and entity
* Create a new OrcidHistory records related to the given profileItem and entity
* items.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param entity the entity item
* @return the created orcid history record
* @throws SQLException if database error
*/
public OrcidHistory create(Context context, Item owner, Item entity) throws SQLException;
public OrcidHistory create(Context context, Item profileItem, Item entity) throws SQLException;
/**
* Delete an OrcidHistory
@@ -96,23 +97,23 @@ public interface OrcidHistoryService {
public void update(Context context, OrcidHistory orcidHistory) throws SQLException;
/**
* Find the last put code related to the given owner and entity item.
* Find the last put code related to the given profileItem and entity item.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param entity the entity item
* @return the found put code, if any
* @throws SQLException if database error
*/
public Optional<String> findLastPutCode(Context context, Item owner, Item entity) throws SQLException;
public Optional<String> findLastPutCode(Context context, Item profileItem, Item entity) throws SQLException;
/**
* Find all the last put code related to the entity item each associated with
* the owner to which it refers.
* the profileItem to which it refers.
*
* @param context DSpace context object
* @param entity the entity item
* @return a map that relates the owners with the identified
* @return a map that relates the profileItems with the identified
* putCode
* @throws SQLException if database error
*/

View File

@@ -27,57 +27,58 @@ import org.dspace.core.Context;
public interface OrcidQueueService {
/**
* Create an OrcidQueue record with the given owner and entity. The type of
* operation is calculated based on whether or not the given entity was already
* pushed to the ORCID registry.
* Create an OrcidQueue record with the given profileItem and entity. The type
* of operation is calculated based on whether or not the given entity was
* already pushed to the ORCID registry.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param entity the entity item
* @return the stored record
* @throws SQLException if an SQL error occurs
*/
public OrcidQueue create(Context context, Item owner, Item entity) throws SQLException;
public OrcidQueue create(Context context, Item profileItem, Item entity) throws SQLException;
/**
* Create an OrcidQueue record with the given owner and entity to push new data
* to ORCID.
* Create an OrcidQueue record with the given profileItem and entity to push new
* data to ORCID.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param entity the entity item
* @return the stored record
* @throws SQLException if an SQL error occurs
*/
public OrcidQueue createEntityInsertionRecord(Context context, Item owner, Item entity) throws SQLException;
public OrcidQueue createEntityInsertionRecord(Context context, Item profileItem, Item entity) throws SQLException;
/**
* Create an OrcidQueue record with the given owner to update a record on ORCID
* with the given putCode.
* Create an OrcidQueue record with the given profileItem to update a record on
* ORCID with the given putCode.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param entity the entity item
* @param putCode the putCode related to the given entity item
* @return the stored record
* @throws SQLException if an SQL error occurs
*/
public OrcidQueue createEntityUpdateRecord(Context context, Item owner, Item entity, String putCode)
public OrcidQueue createEntityUpdateRecord(Context context, Item profileItem, Item entity, String putCode)
throws SQLException;
/**
* Create an OrcidQueue record with the given owner to delete a record on ORCID
* related to the given entity type with the given putCode.
* Create an OrcidQueue record with the given profileItem to delete a record on
* ORCID related to the given entity type with the given putCode.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param description the orcid queue record description
* @param type the type of the entity item
* @param putCode the putCode related to the given entity item
* @return the stored record
* @throws SQLException if an SQL error occurs
*/
OrcidQueue createEntityDeletionRecord(Context context, Item owner, String description, String type, String putCode)
OrcidQueue createEntityDeletionRecord(Context context, Item profileItem, String description, String type,
String putCode)
throws SQLException;
/**
@@ -118,48 +119,50 @@ public interface OrcidQueueService {
public List<OrcidQueue> findAll(Context context) throws SQLException;
/**
* Get the orcid queue records by the owner id.
* Get the orcid queue records by the profileItem id.
*
* @param context DSpace context object
* @param ownerId the owner item id
* @return the orcid queue records
* @throws SQLException if an SQL error occurs
* @param context DSpace context object
* @param profileItemId the profileItem item id
* @return the orcid queue records
* @throws SQLException if an SQL error occurs
*/
public List<OrcidQueue> findByOwnerId(Context context, UUID ownerId) throws SQLException;
public List<OrcidQueue> findByProfileItemId(Context context, UUID profileItemId) throws SQLException;
/**
* Get the orcid queue records by the owner id.
* Get the orcid queue records by the profileItem id.
*
* @param context DSpace context object
* @param ownerId the owner item id
* @param limit limit
* @param offset offset
* @return the orcid queue records
* @throws SQLException if an SQL error occurs
* @param context DSpace context object
* @param profileItemId the profileItem item id
* @param limit limit
* @param offset offset
* @return the orcid queue records
* @throws SQLException if an SQL error occurs
*/
public List<OrcidQueue> findByOwnerId(Context context, UUID ownerId, Integer limit, Integer offset)
public List<OrcidQueue> findByProfileItemId(Context context, UUID profileItemId, Integer limit, Integer offset)
throws SQLException;
/**
* Get the orcid queue records by the owner and entity.
* Get the orcid queue records by the profileItem and entity.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param entity the entity item
* @return the found OrcidQueue records
* @throws SQLException if an SQL error occurs
*/
public List<OrcidQueue> findByOwnerAndEntity(Context context, Item owner, Item entity) throws SQLException;
public List<OrcidQueue> findByProfileItemAndEntity(Context context, Item profileItem, Item entity)
throws SQLException;
/**
* Get the OrcidQueue records where the given item is the owner OR the entity
* Get the OrcidQueue records where the given item is the profileItem OR the
* entity
*
* @param context DSpace context object
* @param item the item to search for
* @return the found OrcidQueue records
* @throws SQLException if database error
*/
public List<OrcidQueue> findByOwnerOrEntity(Context context, Item item) throws SQLException;
public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) throws SQLException;
/**
* Get all the OrcidQueue records with attempts less than the given attempts.
@@ -173,14 +176,14 @@ public interface OrcidQueueService {
/**
* Returns the number of records on the OrcidQueue associated with the given
* ownerId.
* profileItemId.
*
* @param context DSpace context object
* @param ownerId the owner item id
* @return the record's count
* @throws SQLException if an SQL error occurs
* @param context DSpace context object
* @param profileItemId the profileItem item id
* @return the record's count
* @throws SQLException if an SQL error occurs
*/
long countByOwnerId(Context context, UUID ownerId) throws SQLException;
long countByProfileItemId(Context context, UUID profileItemId) throws SQLException;
/**
* Delete the OrcidQueue record with the given id.
@@ -212,14 +215,15 @@ public interface OrcidQueueService {
public void deleteByEntityAndRecordType(Context context, Item entity, String recordType) throws SQLException;
/**
* Delete all the OrcidQueue records with the given owner and record type.
* Delete all the OrcidQueue records with the given profileItem and record type.
*
* @param context DSpace context object
* @param owner the owner item
* @param profileItem the profileItem item
* @param recordType the record type
* @throws SQLException if database error occurs
*/
public void deleteByOwnerAndRecordType(Context context, Item owner, String recordType) throws SQLException;
public void deleteByProfileItemAndRecordType(Context context, Item profileItem, String recordType)
throws SQLException;
/**
* Get an OrcidQueue from the database.
@@ -241,16 +245,16 @@ public interface OrcidQueueService {
public void update(Context context, OrcidQueue orcidQueue) throws SQLException;
/**
* Recalculates the ORCID queue records linked to the given owner as regards the
* entities of the given type. The recalculation is done based on the preference
* indicated.
* Recalculates the ORCID queue records linked to the given profileItem as
* regards the entities of the given type. The recalculation is done based on
* the preference indicated.
*
* @param context context
* @param owner the owner
* @param profileItem the profileItem
* @param entityType the entity type related to the records to recalculate
* @param preference the preference value on which to base the recalculation
* @throws SQLException if database error
*/
public void recalculateOrcidQueue(Context context, Item owner, OrcidEntityType entityType,
public void recalculateOrcidQueue(Context context, Item profileItem, OrcidEntityType entityType,
OrcidEntitySyncPreference preference) throws SQLException;
}

View File

@@ -119,7 +119,7 @@ public interface OrcidSynchronizationService {
* @return true if the given entity type can be synchronize with ORCID,
* false otherwise
*/
public boolean isSynchronizationEnabled(Item profile, Item item);
public boolean isSynchronizationAllowed(Item profile, Item item);
/**
* Returns the ORCID synchronization mode configured for the given profile item.

View File

@@ -101,15 +101,15 @@ public class OrcidHistoryServiceImpl implements OrcidHistoryService {
}
@Override
public List<OrcidHistory> findByOwnerOrEntity(Context context, Item owner) throws SQLException {
return orcidHistoryDAO.findByOwnerOrEntity(context, owner);
public List<OrcidHistory> findByProfileItemOrEntity(Context context, Item profileItem) throws SQLException {
return orcidHistoryDAO.findByProfileItemOrEntity(context, profileItem);
}
@Override
public OrcidHistory create(Context context, Item owner, Item entity) throws SQLException {
public OrcidHistory create(Context context, Item profileItem, Item entity) throws SQLException {
OrcidHistory orcidHistory = new OrcidHistory();
orcidHistory.setEntity(entity);
orcidHistory.setOwner(owner);
orcidHistory.setProfileItem(profileItem);
return orcidHistoryDAO.create(context, orcidHistory);
}
@@ -126,26 +126,28 @@ public class OrcidHistoryServiceImpl implements OrcidHistoryService {
}
@Override
public Optional<String> findLastPutCode(Context context, Item owner, Item entity) throws SQLException {
List<OrcidHistory> records = orcidHistoryDAO.findByOwnerAndEntity(context, owner.getID(), entity.getID());
return findLastPutCode(records, owner);
public Optional<String> findLastPutCode(Context context, Item profileItem, Item entity) throws SQLException {
List<OrcidHistory> records = orcidHistoryDAO.findByProfileItemAndEntity(context, profileItem.getID(),
entity.getID());
return findLastPutCode(records, profileItem);
}
@Override
public Map<Item, String> findLastPutCodes(Context context, Item entity) throws SQLException {
Map<Item, String> ownerAndPutCodeMap = new HashMap<Item, String>();
Map<Item, String> profileItemAndPutCodeMap = new HashMap<Item, String>();
List<OrcidHistory> orcidHistoryRecords = findByEntity(context, entity);
for (OrcidHistory orcidHistoryRecord : orcidHistoryRecords) {
Item owner = orcidHistoryRecord.getOwner();
if (ownerAndPutCodeMap.containsKey(owner)) {
Item profileItem = orcidHistoryRecord.getProfileItem();
if (profileItemAndPutCodeMap.containsKey(profileItem)) {
continue;
}
findLastPutCode(orcidHistoryRecords, owner).ifPresent(putCode -> ownerAndPutCodeMap.put(owner, putCode));
findLastPutCode(orcidHistoryRecords, profileItem)
.ifPresent(putCode -> profileItemAndPutCodeMap.put(profileItem, putCode));
}
return ownerAndPutCodeMap;
return profileItemAndPutCodeMap;
}
@Override
@@ -163,15 +165,15 @@ public class OrcidHistoryServiceImpl implements OrcidHistoryService {
public OrcidHistory synchronizeWithOrcid(Context context, OrcidQueue orcidQueue, boolean forceAddition)
throws SQLException {
Item owner = orcidQueue.getOwner();
Item profileItem = orcidQueue.getProfileItem();
String orcid = getMetadataValue(owner, "person.identifier.orcid")
String orcid = getMetadataValue(profileItem, "person.identifier.orcid")
.orElseThrow(() -> new IllegalArgumentException(
format("The related owner item (id = %s) does not have an orcid", owner.getID())));
format("The related profileItem item (id = %s) does not have an orcid", profileItem.getID())));
String token = getAccessToken(context, owner)
String token = getAccessToken(context, profileItem)
.orElseThrow(() -> new IllegalArgumentException(
format("The related owner item (id = %s) does not have an access token", owner.getID())));
format("The related profileItem item (id = %s) does not have an access token", profileItem.getID())));
OrcidOperation operation = calculateOperation(orcidQueue, forceAddition);
@@ -304,7 +306,7 @@ public class OrcidHistoryServiceImpl implements OrcidHistoryService {
OrcidOperation operation, int status, String putCode) throws SQLException {
OrcidHistory history = new OrcidHistory();
history.setEntity(orcidQueue.getEntity());
history.setOwner(orcidQueue.getOwner());
history.setProfileItem(orcidQueue.getProfileItem());
history.setResponseMessage(responseMessage);
history.setStatus(status);
history.setPutCode(putCode);
@@ -333,9 +335,9 @@ public class OrcidHistoryServiceImpl implements OrcidHistoryService {
return OrcidEntityType.isValidEntityType(orcidQueue.getRecordType());
}
private Optional<String> findLastPutCode(List<OrcidHistory> orcidHistoryRecords, Item owner) {
private Optional<String> findLastPutCode(List<OrcidHistory> orcidHistoryRecords, Item profileItem) {
return orcidHistoryRecords.stream()
.filter(orcidHistoryRecord -> owner.equals(orcidHistoryRecord.getOwner()))
.filter(orcidHistoryRecord -> profileItem.equals(orcidHistoryRecord.getProfileItem()))
.sorted(comparing(OrcidHistory::getTimestamp, nullsFirst(naturalOrder())).reversed())
.map(history -> history.getPutCode())
.filter(putCode -> isNotBlank(putCode))

View File

@@ -49,29 +49,30 @@ public class OrcidQueueServiceImpl implements OrcidQueueService {
private RelationshipService relationshipService;
@Override
public List<OrcidQueue> findByOwnerId(Context context, UUID ownerId) throws SQLException {
return orcidQueueDAO.findByOwnerId(context, ownerId, -1, 0);
public List<OrcidQueue> findByProfileItemId(Context context, UUID profileItemId) throws SQLException {
return orcidQueueDAO.findByProfileItemId(context, profileItemId, -1, 0);
}
@Override
public List<OrcidQueue> findByOwnerId(Context context, UUID ownerId, Integer limit, Integer offset)
public List<OrcidQueue> findByProfileItemId(Context context, UUID profileItemId, Integer limit, Integer offset)
throws SQLException {
return orcidQueueDAO.findByOwnerId(context, ownerId, limit, offset);
return orcidQueueDAO.findByProfileItemId(context, profileItemId, limit, offset);
}
@Override
public List<OrcidQueue> findByOwnerAndEntity(Context context, Item owner, Item entity) throws SQLException {
return orcidQueueDAO.findByOwnerAndEntity(context, owner, entity);
public List<OrcidQueue> findByProfileItemAndEntity(Context context, Item profileItem, Item entity)
throws SQLException {
return orcidQueueDAO.findByProfileItemAndEntity(context, profileItem, entity);
}
@Override
public List<OrcidQueue> findByOwnerOrEntity(Context context, Item item) throws SQLException {
return orcidQueueDAO.findByOwnerOrEntity(context, item);
public List<OrcidQueue> findByProfileItemOrEntity(Context context, Item item) throws SQLException {
return orcidQueueDAO.findByProfileItemOrEntity(context, item);
}
@Override
public long countByOwnerId(Context context, UUID ownerId) throws SQLException {
return orcidQueueDAO.countByOwnerId(context, ownerId);
public long countByProfileItemId(Context context, UUID profileItemId) throws SQLException {
return orcidQueueDAO.countByProfileItemId(context, profileItemId);
}
@Override
@@ -80,31 +81,31 @@ public class OrcidQueueServiceImpl implements OrcidQueueService {
}
@Override
public OrcidQueue create(Context context, Item owner, Item entity) throws SQLException {
Optional<String> putCode = orcidHistoryService.findLastPutCode(context, owner, entity);
public OrcidQueue create(Context context, Item profileItem, Item entity) throws SQLException {
Optional<String> putCode = orcidHistoryService.findLastPutCode(context, profileItem, entity);
if (putCode.isPresent()) {
return createEntityUpdateRecord(context, owner, entity, putCode.get());
return createEntityUpdateRecord(context, profileItem, entity, putCode.get());
} else {
return createEntityInsertionRecord(context, owner, entity);
return createEntityInsertionRecord(context, profileItem, entity);
}
}
@Override
public OrcidQueue createEntityInsertionRecord(Context context, Item owner, Item entity) throws SQLException {
public OrcidQueue createEntityInsertionRecord(Context context, Item profileItem, Item entity) throws SQLException {
OrcidQueue orcidQueue = new OrcidQueue();
orcidQueue.setEntity(entity);
orcidQueue.setRecordType(itemService.getEntityTypeLabel(entity));
orcidQueue.setOwner(owner);
orcidQueue.setProfileItem(profileItem);
orcidQueue.setDescription(getMetadataValue(entity, "dc.title"));
orcidQueue.setOperation(OrcidOperation.INSERT);
return orcidQueueDAO.create(context, orcidQueue);
}
@Override
public OrcidQueue createEntityUpdateRecord(Context context, Item owner, Item entity, String putCode)
public OrcidQueue createEntityUpdateRecord(Context context, Item profileItem, Item entity, String putCode)
throws SQLException {
OrcidQueue orcidQueue = new OrcidQueue();
orcidQueue.setOwner(owner);
orcidQueue.setProfileItem(profileItem);
orcidQueue.setEntity(entity);
orcidQueue.setPutCode(putCode);
orcidQueue.setRecordType(itemService.getEntityTypeLabel(entity));
@@ -114,12 +115,12 @@ public class OrcidQueueServiceImpl implements OrcidQueueService {
}
@Override
public OrcidQueue createEntityDeletionRecord(Context context, Item owner, String description, String type,
public OrcidQueue createEntityDeletionRecord(Context context, Item profileItem, String description, String type,
String putCode)
throws SQLException {
OrcidQueue orcidQueue = new OrcidQueue();
orcidQueue.setRecordType(type);
orcidQueue.setOwner(owner);
orcidQueue.setProfileItem(profileItem);
orcidQueue.setPutCode(putCode);
orcidQueue.setDescription(description);
orcidQueue.setOperation(OrcidOperation.DELETE);
@@ -132,7 +133,7 @@ public class OrcidQueueServiceImpl implements OrcidQueueService {
OrcidQueue orcidQueue = new OrcidQueue();
orcidQueue.setEntity(profile);
orcidQueue.setRecordType(recordType);
orcidQueue.setOwner(profile);
orcidQueue.setProfileItem(profile);
orcidQueue.setDescription(description);
orcidQueue.setMetadata(metadata);
orcidQueue.setOperation(OrcidOperation.INSERT);
@@ -145,7 +146,7 @@ public class OrcidQueueServiceImpl implements OrcidQueueService {
OrcidQueue orcidQueue = new OrcidQueue();
orcidQueue.setEntity(profile);
orcidQueue.setRecordType(recordType);
orcidQueue.setOwner(profile);
orcidQueue.setProfileItem(profile);
orcidQueue.setDescription(description);
orcidQueue.setPutCode(putCode);
orcidQueue.setMetadata(metadata);
@@ -180,8 +181,9 @@ public class OrcidQueueServiceImpl implements OrcidQueueService {
}
@Override
public void deleteByOwnerAndRecordType(Context context, Item owner, String recordType) throws SQLException {
List<OrcidQueue> records = orcidQueueDAO.findByOwnerAndRecordType(context, owner, recordType);
public void deleteByProfileItemAndRecordType(Context context, Item profileItem, String recordType)
throws SQLException {
List<OrcidQueue> records = orcidQueueDAO.findByProfileItemAndRecordType(context, profileItem, recordType);
for (OrcidQueue record : records) {
orcidQueueDAO.delete(context, record);
}
@@ -198,16 +200,16 @@ public class OrcidQueueServiceImpl implements OrcidQueueService {
}
@Override
public void recalculateOrcidQueue(Context context, Item owner, OrcidEntityType orcidEntityType,
public void recalculateOrcidQueue(Context context, Item profileItem, OrcidEntityType orcidEntityType,
OrcidEntitySyncPreference preference) throws SQLException {
String entityType = orcidEntityType.getEntityType();
if (preference == OrcidEntitySyncPreference.DISABLED) {
deleteByOwnerAndRecordType(context, owner, entityType);
deleteByProfileItemAndRecordType(context, profileItem, entityType);
} else {
List<Item> entities = findAllEntitiesLinkableWith(context, owner, entityType);
List<Item> entities = findAllEntitiesLinkableWith(context, profileItem, entityType);
for (Item entity : entities) {
create(context, owner, entity);
create(context, profileItem, entity);
}
}

View File

@@ -159,7 +159,11 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
}
@Override
public boolean isSynchronizationEnabled(Item profile, Item item) {
public boolean isSynchronizationAllowed(Item profile, Item item) {
if (isOrcidSynchronizationDisabled()) {
return false;
}
String entityType = itemService.getEntityTypeLabel(item);
if (entityType == null) {
@@ -280,6 +284,10 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
}
private boolean isOrcidSynchronizationDisabled() {
return !configurationService.getBooleanProperty("orcid.synchronization-enabled", true);
}
private void updateItem(Context context, Item item) throws SQLException {
try {
context.turnOffAuthorisationSystem();

View File

@@ -30,6 +30,7 @@ import org.apache.logging.log4j.Logger;
import org.dspace.app.orcid.OrcidHistory;
import org.dspace.app.orcid.OrcidQueue;
import org.dspace.app.orcid.OrcidToken;
import org.dspace.app.orcid.model.OrcidEntityType;
import org.dspace.app.orcid.service.OrcidHistoryService;
import org.dspace.app.orcid.service.OrcidQueueService;
import org.dspace.app.orcid.service.OrcidSynchronizationService;
@@ -1653,9 +1654,13 @@ prevent the generation of resource policy entry values with null dspace_object a
private void removeOrcidSynchronizationStuff(Context context, Item item) throws SQLException, AuthorizeException {
try {
if (isNotProfileOrOrcidEntity(item)) {
return;
}
context.turnOffAuthorisationSystem();
context.turnOffAuthorisationSystem();
try {
createOrcidQueueRecordsToDeleteOnOrcid(context, item);
deleteOrcidHistoryRecords(context, item);
@@ -1667,28 +1672,34 @@ prevent the generation of resource policy entry values with null dspace_object a
}
private boolean isNotProfileOrOrcidEntity(Item item) {
String entityType = getEntityTypeLabel(item);
return !OrcidEntityType.isValidEntityType(entityType)
&& !researcherProfileService.getProfileType().equals(entityType);
}
private void createOrcidQueueRecordsToDeleteOnOrcid(Context context, Item entity) throws SQLException {
String entityType = getEntityTypeLabel(entity);
if (researcherProfileService.getProfileType().equals(entityType)) {
if (entityType == null || researcherProfileService.getProfileType().equals(entityType)) {
return;
}
Map<Item, String> ownerAndPutCodeMap = orcidHistoryService.findLastPutCodes(context, entity);
for (Item owner : ownerAndPutCodeMap.keySet()) {
if (orcidSynchronizationService.isSynchronizationEnabled(owner, entity)) {
String putCode = ownerAndPutCodeMap.get(owner);
Map<Item, String> profileAndPutCodeMap = orcidHistoryService.findLastPutCodes(context, entity);
for (Item profile : profileAndPutCodeMap.keySet()) {
if (orcidSynchronizationService.isSynchronizationAllowed(profile, entity)) {
String putCode = profileAndPutCodeMap.get(profile);
String title = getMetadataFirstValue(entity, "dc", "title", null, Item.ANY);
orcidQueueService.createEntityDeletionRecord(context, owner, title, entityType, putCode);
orcidQueueService.createEntityDeletionRecord(context, profile, title, entityType, putCode);
}
}
}
private void deleteOrcidHistoryRecords(Context context, Item item) throws SQLException {
List<OrcidHistory> historyRecords = orcidHistoryService.findByOwnerOrEntity(context, item);
List<OrcidHistory> historyRecords = orcidHistoryService.findByProfileItemOrEntity(context, item);
for (OrcidHistory historyRecord : historyRecords) {
if (historyRecord.getOwner().equals(item)) {
if (historyRecord.getProfileItem().equals(item)) {
orcidHistoryService.delete(context, historyRecord);
} else {
historyRecord.setEntity(null);
@@ -1698,7 +1709,7 @@ prevent the generation of resource policy entry values with null dspace_object a
}
private void deleteOrcidQueueRecords(Context context, Item item) throws SQLException {
List<OrcidQueue> orcidQueueRecords = orcidQueueService.findByOwnerOrEntity(context, item);
List<OrcidQueue> orcidQueueRecords = orcidQueueService.findByProfileItemOrEntity(context, item);
for (OrcidQueue orcidQueueRecord : orcidQueueRecords) {
orcidQueueService.delete(context, orcidQueueRecord);
}

View File

@@ -26,7 +26,7 @@ import org.hamcrest.TypeSafeMatcher;
*/
public class OrcidQueueMatcher extends TypeSafeMatcher<OrcidQueue> {
private final Matcher<Item> ownerMatcher;
private final Matcher<Item> profileItemMatcher;
private final Matcher<Item> entityMatcher;
@@ -42,11 +42,11 @@ public class OrcidQueueMatcher extends TypeSafeMatcher<OrcidQueue> {
private final Matcher<Integer> attemptsMatcher;
private OrcidQueueMatcher(Matcher<Item> ownerMatcher, Matcher<Item> entityMatcher,
private OrcidQueueMatcher(Matcher<Item> profileItemMatcher, Matcher<Item> entityMatcher,
Matcher<String> recordTypeMatcher, Matcher<String> putCodeMatcher, Matcher<String> metadataMatcher,
Matcher<String> descriptionMatcher, Matcher<OrcidOperation> operationMatcher,
Matcher<Integer> attemptsMatcher) {
this.ownerMatcher = ownerMatcher;
this.profileItemMatcher = profileItemMatcher;
this.entityMatcher = entityMatcher;
this.recordTypeMatcher = recordTypeMatcher;
this.putCodeMatcher = putCodeMatcher;
@@ -56,26 +56,27 @@ public class OrcidQueueMatcher extends TypeSafeMatcher<OrcidQueue> {
this.attemptsMatcher = attemptsMatcher;
}
public static OrcidQueueMatcher matches(Item owner, Item entity, String recordType, OrcidOperation operation) {
return new OrcidQueueMatcher(is(owner), is(entity), is(recordType), anything(),
public static OrcidQueueMatcher matches(Item profileItem, Item entity, String recordType,
OrcidOperation operation) {
return new OrcidQueueMatcher(is(profileItem), is(entity), is(recordType), anything(),
anything(), anything(), is(operation), anything());
}
public static OrcidQueueMatcher matches(Item owner, Item entity, String recordType,
public static OrcidQueueMatcher matches(Item profileItem, Item entity, String recordType,
OrcidOperation operation, int attempts) {
return new OrcidQueueMatcher(is(owner), is(entity), is(recordType), anything(),
return new OrcidQueueMatcher(is(profileItem), is(entity), is(recordType), anything(),
anything(), anything(), is(operation), is(attempts));
}
public static OrcidQueueMatcher matches(Item owner, Item entity, String recordType,
public static OrcidQueueMatcher matches(Item profileItem, Item entity, String recordType,
String putCode, OrcidOperation operation) {
return new OrcidQueueMatcher(is(owner), is(entity), is(recordType), is(putCode),
return new OrcidQueueMatcher(is(profileItem), is(entity), is(recordType), is(putCode),
anything(), anything(), is(operation), anything());
}
public static OrcidQueueMatcher matches(Item owner, Item entity, String recordType,
public static OrcidQueueMatcher matches(Item profileItem, Item entity, String recordType,
String putCode, String metadata, String description, OrcidOperation operation) {
return new OrcidQueueMatcher(is(owner), is(entity), is(recordType),
return new OrcidQueueMatcher(is(profileItem), is(entity), is(recordType),
is(putCode), is(metadata), is(description), is(operation), anything());
}
@@ -85,16 +86,16 @@ public class OrcidQueueMatcher extends TypeSafeMatcher<OrcidQueue> {
is(putCode), is(metadata), is(description), is(operation), anything());
}
public static OrcidQueueMatcher matches(Item owner, Item entity, String recordType,
public static OrcidQueueMatcher matches(Item profileItem, Item entity, String recordType,
String putCode, Matcher<String> metadata, String description, OrcidOperation operation) {
return new OrcidQueueMatcher(is(owner), is(entity), is(recordType),
return new OrcidQueueMatcher(is(profileItem), is(entity), is(recordType),
is(putCode), metadata, is(description), is(operation), anything());
}
@Override
public void describeTo(Description description) {
description.appendText("an orcid queue record that with the following attributes:")
.appendText(" item owner ").appendDescriptionOf(ownerMatcher)
.appendText(" item profileItem ").appendDescriptionOf(profileItemMatcher)
.appendText(", item entity ").appendDescriptionOf(entityMatcher)
.appendText(", record type ").appendDescriptionOf(recordTypeMatcher)
.appendText(", metadata ").appendDescriptionOf(metadataMatcher)
@@ -106,7 +107,7 @@ public class OrcidQueueMatcher extends TypeSafeMatcher<OrcidQueue> {
@Override
protected boolean matchesSafely(OrcidQueue item) {
return ownerMatcher.matches(item.getOwner())
return profileItemMatcher.matches(item.getProfileItem())
&& entityMatcher.matches(item.getEntity())
&& recordTypeMatcher.matches(item.getRecordType())
&& metadataMatcher.matches(item.getMetadata())

View File

@@ -92,6 +92,28 @@ public class OrcidQueueConsumerIT extends AbstractIntegrationTestWithDatabase {
context.setDispatcher(null);
}
@Test
public void testWithNotOrcidSynchronizationEntity() throws Exception {
context.turnOffAuthorisationSystem();
Collection orgUnits = CollectionBuilder.createCollection(context, parentCommunity)
.withName("OrgUnits")
.withEntityType("OrgUnit")
.build();
ItemBuilder.createItem(context, orgUnits)
.withTitle("Test OrgUnit")
.withSubject("test")
.build();
context.restoreAuthSystemState();
context.commit();
List<OrcidQueue> queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, empty());
}
@Test
public void testWithOrcidSynchronizationDisabled() throws Exception {

View File

@@ -18,6 +18,7 @@ import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZA
import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZATION_CITY_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZATION_COUNTRY_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.ORGANIZATION_NAME_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.PUBLICATION_DATE_INVALID;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.TITLE_REQUIRED;
import static org.dspace.app.orcid.model.validator.OrcidValidationError.TYPE_REQUIRED;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -43,7 +44,9 @@ import org.orcid.jaxb.model.v3.release.common.Amount;
import org.orcid.jaxb.model.v3.release.common.DisambiguatedOrganization;
import org.orcid.jaxb.model.v3.release.common.Organization;
import org.orcid.jaxb.model.v3.release.common.OrganizationAddress;
import org.orcid.jaxb.model.v3.release.common.PublicationDate;
import org.orcid.jaxb.model.v3.release.common.Title;
import org.orcid.jaxb.model.v3.release.common.Year;
import org.orcid.jaxb.model.v3.release.record.ExternalID;
import org.orcid.jaxb.model.v3.release.record.ExternalIDs;
import org.orcid.jaxb.model.v3.release.record.Funding;
@@ -180,6 +183,64 @@ public class OrcidValidatorTest {
assertThat(errors, containsInAnyOrder(EXTERNAL_ID_REQUIRED));
}
@Test
public void testdWorkWithPublicationDateWithoutYear() {
Work work = new Work();
work.setWorkTitle(new WorkTitle());
work.setWorkType(WorkType.DATA_SET);
work.getWorkTitle().setTitle(new Title("Work title"));
work.setWorkExternalIdentifiers(new ExternalIDs());
work.getExternalIdentifiers().getExternalIdentifier().add(buildValidExternalID());
PublicationDate publicationDate = new PublicationDate();
work.setPublicationDate(publicationDate);
List<OrcidValidationError> errors = validator.validateWork(work);
assertThat(errors, hasSize(1));
assertThat(errors, containsInAnyOrder(PUBLICATION_DATE_INVALID));
}
@Test
public void testdWorkWithPublicationDateWithInvalidYear() {
Work work = new Work();
work.setWorkTitle(new WorkTitle());
work.setWorkType(WorkType.DATA_SET);
work.getWorkTitle().setTitle(new Title("Work title"));
work.setWorkExternalIdentifiers(new ExternalIDs());
work.getExternalIdentifiers().getExternalIdentifier().add(buildValidExternalID());
PublicationDate publicationDate = new PublicationDate();
Year year = new Year();
year.setValue("INVALID");
publicationDate.setYear(year);
work.setPublicationDate(publicationDate);
List<OrcidValidationError> errors = validator.validateWork(work);
assertThat(errors, hasSize(1));
assertThat(errors, containsInAnyOrder(PUBLICATION_DATE_INVALID));
}
@Test
public void testdWorkWithPublicationDateWithYearPriorTo1900() {
Work work = new Work();
work.setWorkTitle(new WorkTitle());
work.setWorkType(WorkType.DATA_SET);
work.getWorkTitle().setTitle(new Title("Work title"));
work.setWorkExternalIdentifiers(new ExternalIDs());
work.getExternalIdentifiers().getExternalIdentifier().add(buildValidExternalID());
PublicationDate publicationDate = new PublicationDate();
publicationDate.setYear(new Year(1850));
work.setPublicationDate(publicationDate);
List<OrcidValidationError> errors = validator.validateWork(work);
assertThat(errors, hasSize(1));
assertThat(errors, containsInAnyOrder(PUBLICATION_DATE_INVALID));
}
@Test
public void testValidWork() {
@@ -190,6 +251,10 @@ public class OrcidValidatorTest {
work.setWorkExternalIdentifiers(new ExternalIDs());
work.getExternalIdentifiers().getExternalIdentifier().add(buildValidExternalID());
PublicationDate publicationDate = new PublicationDate();
publicationDate.setYear(new Year(1956));
work.setPublicationDate(publicationDate);
List<OrcidValidationError> errors = validator.validateWork(work);
assertThat(errors, empty());
}

View File

@@ -143,9 +143,9 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
.build();
context.restoreAuthSystemState();
Item firstOwner = createOwnerItem("0000-1111-2222-3333", eperson, BATCH);
Item secondOwner = createOwnerItem("1111-2222-3333-4444", admin, MANUAL);
Item thirdOwner = createOwnerItem("2222-3333-4444-5555", owner, BATCH);
Item firstProfileItem = createProfileItemItem("0000-1111-2222-3333", eperson, BATCH);
Item secondProfileItem = createProfileItemItem("1111-2222-3333-4444", admin, MANUAL);
Item thirdProfileItem = createProfileItemItem("2222-3333-4444-5555", owner, BATCH);
Item firstEntity = createPublication("First publication");
Item secondEntity = createPublication("Second publication");
@@ -165,30 +165,30 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
when(orcidClientMock.push(any(), eq("2222-3333-4444-5555"), any()))
.thenReturn(createdResponse("11111"));
createOrcidQueue(context, firstOwner, firstEntity);
createOrcidQueue(context, firstOwner, secondEntity, "98765");
createOrcidQueue(context, firstOwner, "Description", "Publication", "22222");
createOrcidQueue(context, secondOwner, thirdEntity);
createOrcidQueue(context, secondOwner, fourthEntity);
createOrcidQueue(context, thirdOwner, fifthEntity);
createOrcidQueue(context, firstProfileItem, firstEntity);
createOrcidQueue(context, firstProfileItem, secondEntity, "98765");
createOrcidQueue(context, firstProfileItem, "Description", "Publication", "22222");
createOrcidQueue(context, secondProfileItem, thirdEntity);
createOrcidQueue(context, secondProfileItem, fourthEntity);
createOrcidQueue(context, thirdProfileItem, fifthEntity);
context.commit();
TestDSpaceRunnableHandler handler = runBulkSynchronization(false);
String firstOwnerId = firstOwner.getID().toString();
String thirdOwnerId = thirdOwner.getID().toString();
String firstProfileItemId = firstProfileItem.getID().toString();
String thirdProfileItemId = thirdProfileItem.getID().toString();
assertThat(handler.getInfoMessages(), hasSize(9));
assertThat(handler.getInfoMessages(), containsInAnyOrder(
"Found 4 queue records to synchronize with ORCID",
"Addition of Publication for profile with ID: " + firstOwnerId,
"Addition of Publication for profile with ID: " + firstProfileItemId,
"History record created with status 201. The operation was completed successfully",
"Update of Publication for profile with ID: " + firstOwnerId + " by put code 98765",
"Update of Publication for profile with ID: " + firstProfileItemId + " by put code 98765",
"History record created with status 200. The operation was completed successfully",
"Deletion of Publication for profile with ID: " + firstOwnerId + " by put code 22222",
"Deletion of Publication for profile with ID: " + firstProfileItemId + " by put code 22222",
"History record created with status 204. The operation was completed successfully",
"Addition of Publication for profile with ID: " + thirdOwnerId,
"Addition of Publication for profile with ID: " + thirdProfileItemId,
"History record created with status 201. The operation was completed successfully"));
assertThat(handler.getErrorMessages(), empty());
@@ -203,23 +203,23 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
List<OrcidQueue> queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(2));
assertThat(queueRecords, hasItem(matches(secondOwner, thirdEntity, "Publication", INSERT, 0)));
assertThat(queueRecords, hasItem(matches(secondOwner, fourthEntity, "Publication", INSERT, 0)));
assertThat(queueRecords, hasItem(matches(secondProfileItem, thirdEntity, "Publication", INSERT, 0)));
assertThat(queueRecords, hasItem(matches(secondProfileItem, fourthEntity, "Publication", INSERT, 0)));
List<OrcidHistory> historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(4));
assertThat(historyRecords, hasItem(matches(history(firstOwner, firstEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(firstOwner, secondEntity, 200, UPDATE))));
assertThat(historyRecords, hasItem(matches(history(firstOwner, 204, DELETE))));
assertThat(historyRecords, hasItem(matches(history(thirdOwner, fifthEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(firstProfileItem, firstEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(firstProfileItem, secondEntity, 200, UPDATE))));
assertThat(historyRecords, hasItem(matches(history(firstProfileItem, 204, DELETE))));
assertThat(historyRecords, hasItem(matches(history(thirdProfileItem, fifthEntity, 201, INSERT))));
}
@Test
public void testWithOneValidationError() throws Exception {
Item firstOwner = createOwnerItem("0000-1111-2222-3333", eperson, BATCH);
Item secondOwner = createOwnerItem("1111-2222-3333-4444", admin, BATCH);
Item firstProfileItem = createProfileItemItem("0000-1111-2222-3333", eperson, BATCH);
Item secondProfileItem = createProfileItemItem("1111-2222-3333-4444", admin, BATCH);
Item firstEntity = createPublication("First publication");
Item secondEntity = createPublication("");
@@ -231,9 +231,9 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
when(orcidClientMock.push(any(), eq("1111-2222-3333-4444"), any()))
.thenReturn(createdResponse("55555"));
createOrcidQueue(context, firstOwner, firstEntity);
createOrcidQueue(context, firstOwner, secondEntity, "98765");
createOrcidQueue(context, secondOwner, thirdEntity);
createOrcidQueue(context, firstProfileItem, firstEntity);
createOrcidQueue(context, firstProfileItem, secondEntity, "98765");
createOrcidQueue(context, secondProfileItem, thirdEntity);
context.commit();
@@ -242,10 +242,10 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
assertThat(handler.getInfoMessages(), hasSize(6));
assertThat(handler.getInfoMessages(), containsInAnyOrder(
"Found 3 queue records to synchronize with ORCID",
"Addition of Publication for profile with ID: " + firstOwner.getID().toString(),
"Addition of Publication for profile with ID: " + firstProfileItem.getID().toString(),
"History record created with status 201. The operation was completed successfully",
"Update of Publication for profile with ID: " + firstOwner.getID().toString() + " by put code 98765",
"Addition of Publication for profile with ID: " + secondOwner.getID().toString(),
"Update of Publication for profile with ID: " + firstProfileItem.getID().toString() + " by put code 98765",
"Addition of Publication for profile with ID: " + secondProfileItem.getID().toString(),
"History record created with status 201. The operation was completed successfully"));
assertThat(handler.getErrorMessages(), hasSize(1));
@@ -260,20 +260,20 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
List<OrcidQueue> queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, hasItem(matches(firstOwner, secondEntity, "Publication", UPDATE, 1)));
assertThat(queueRecords, hasItem(matches(firstProfileItem, secondEntity, "Publication", UPDATE, 1)));
List<OrcidHistory> historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(2));
assertThat(historyRecords, hasItem(matches(history(firstOwner, firstEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(secondOwner, thirdEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(firstProfileItem, firstEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(secondProfileItem, thirdEntity, 201, INSERT))));
}
@Test
public void testWithUnexpectedErrorForMissingOrcid() throws Exception {
Item firstOwner = createOwnerItem("0000-1111-2222-3333", eperson, BATCH);
Item secondOwner = createOwnerItem("", admin, BATCH);
Item firstProfileItem = createProfileItemItem("0000-1111-2222-3333", eperson, BATCH);
Item secondProfileItem = createProfileItemItem("", admin, BATCH);
Item firstEntity = createPublication("First publication");
Item secondEntity = createPublication("Second publication");
@@ -281,8 +281,8 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
when(orcidClientMock.push(any(), eq("0000-1111-2222-3333"), any()))
.thenReturn(createdResponse("12345"));
createOrcidQueue(context, secondOwner, secondEntity);
createOrcidQueue(context, firstOwner, firstEntity);
createOrcidQueue(context, secondProfileItem, secondEntity);
createOrcidQueue(context, firstProfileItem, firstEntity);
context.commit();
@@ -291,13 +291,13 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
assertThat(handler.getInfoMessages(), hasSize(4));
assertThat(handler.getInfoMessages(), containsInAnyOrder(
"Found 2 queue records to synchronize with ORCID",
"Addition of Publication for profile with ID: " + secondOwner.getID().toString(),
"Addition of Publication for profile with ID: " + firstOwner.getID().toString(),
"Addition of Publication for profile with ID: " + secondProfileItem.getID().toString(),
"Addition of Publication for profile with ID: " + firstProfileItem.getID().toString(),
"History record created with status 201. The operation was completed successfully"));
assertThat(handler.getErrorMessages(), hasSize(1));
assertThat(handler.getErrorMessages(), contains("An unexpected error occurs during the synchronization: "
+ "The related owner item (id = " + secondOwner.getID() + ") does not have an orcid"));
+ "The related profileItem item (id = " + secondProfileItem.getID() + ") does not have an orcid"));
assertThat(handler.getWarningMessages(), empty());
@@ -306,19 +306,19 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
List<OrcidQueue> queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, hasItem(matches(secondOwner, secondEntity, "Publication", INSERT, 1)));
assertThat(queueRecords, hasItem(matches(secondProfileItem, secondEntity, "Publication", INSERT, 1)));
List<OrcidHistory> historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(1));
assertThat(historyRecords, hasItem(matches(history(firstOwner, firstEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(firstProfileItem, firstEntity, 201, INSERT))));
}
@Test
public void testWithOrcidClientException() throws Exception {
Item firstOwner = createOwnerItem("0000-1111-2222-3333", eperson, BATCH);
Item secondOwner = createOwnerItem("1111-2222-3333-4444", admin, BATCH);
Item firstProfileItem = createProfileItemItem("0000-1111-2222-3333", eperson, BATCH);
Item secondProfileItem = createProfileItemItem("1111-2222-3333-4444", admin, BATCH);
Item firstEntity = createPublication("First publication");
Item secondEntity = createPublication("Second publication");
@@ -329,8 +329,8 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
when(orcidClientMock.push(any(), eq("1111-2222-3333-4444"), any()))
.thenReturn(createdResponse("55555"));
createOrcidQueue(context, firstOwner, firstEntity);
createOrcidQueue(context, secondOwner, secondEntity);
createOrcidQueue(context, firstProfileItem, firstEntity);
createOrcidQueue(context, secondProfileItem, secondEntity);
context.commit();
@@ -339,9 +339,9 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
assertThat(handler.getInfoMessages(), hasSize(5));
assertThat(handler.getInfoMessages(), containsInAnyOrder(
"Found 2 queue records to synchronize with ORCID",
"Addition of Publication for profile with ID: " + firstOwner.getID().toString(),
"Addition of Publication for profile with ID: " + firstProfileItem.getID().toString(),
"History record created with status 400. The resource sent to ORCID registry is not valid",
"Addition of Publication for profile with ID: " + secondOwner.getID().toString(),
"Addition of Publication for profile with ID: " + secondProfileItem.getID().toString(),
"History record created with status 201. The operation was completed successfully"));
assertThat(handler.getErrorMessages(), empty());
@@ -353,12 +353,12 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
List<OrcidQueue> queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, hasItem(matches(firstOwner, firstEntity, "Publication", INSERT, 1)));
assertThat(queueRecords, hasItem(matches(firstProfileItem, firstEntity, "Publication", INSERT, 1)));
List<OrcidHistory> historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(2));
assertThat(historyRecords, hasItem(matches(history(firstOwner, firstEntity, 400, INSERT))));
assertThat(historyRecords, hasItem(matches(history(secondOwner, secondEntity, 201, INSERT))));
assertThat(historyRecords, hasItem(matches(history(firstProfileItem, firstEntity, 400, INSERT))));
assertThat(historyRecords, hasItem(matches(history(secondProfileItem, secondEntity, 201, INSERT))));
}
@@ -368,13 +368,13 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
configurationService.setProperty("orcid.bulk-synchronization.max-attempts", 2);
Item owner = createOwnerItem("0000-1111-2222-3333", eperson, BATCH);
Item profileItem = createProfileItemItem("0000-1111-2222-3333", eperson, BATCH);
Item entity = createPublication("First publication");
when(orcidClientMock.push(any(), eq("0000-1111-2222-3333"), any()))
.thenThrow(new OrcidClientException(400, "Bad request"));
createOrcidQueue(context, owner, entity);
createOrcidQueue(context, profileItem, entity);
// First attempt
@@ -385,11 +385,11 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
List<OrcidQueue> queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, hasItem(matches(owner, entity, "Publication", INSERT, 1)));
assertThat(queueRecords, hasItem(matches(profileItem, entity, "Publication", INSERT, 1)));
List<OrcidHistory> historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(1));
assertThat(historyRecords, hasItem(matches(history(owner, entity, 400, INSERT))));
assertThat(historyRecords, hasItem(matches(history(profileItem, entity, 400, INSERT))));
// Second attempt
@@ -400,12 +400,12 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, hasItem(matches(owner, entity, "Publication", INSERT, 2)));
assertThat(queueRecords, hasItem(matches(profileItem, entity, "Publication", INSERT, 2)));
historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(2));
assertThat(historyRecords, contains(matches(history(owner, entity, 400, INSERT)),
matches(history(owner, entity, 400, INSERT))));
assertThat(historyRecords, contains(matches(history(profileItem, entity, 400, INSERT)),
matches(history(profileItem, entity, 400, INSERT))));
// Third attempt
@@ -416,12 +416,12 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, hasItem(matches(owner, entity, "Publication", INSERT, 2)));
assertThat(queueRecords, hasItem(matches(profileItem, entity, "Publication", INSERT, 2)));
historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(2));
assertThat(historyRecords, contains(matches(history(owner, entity, 400, INSERT)),
matches(history(owner, entity, 400, INSERT))));
assertThat(historyRecords, contains(matches(history(profileItem, entity, 400, INSERT)),
matches(history(profileItem, entity, 400, INSERT))));
// Fourth attempt forcing synchronization
@@ -432,24 +432,24 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
queueRecords = orcidQueueService.findAll(context);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, hasItem(matches(owner, entity, "Publication", INSERT, 3)));
assertThat(queueRecords, hasItem(matches(profileItem, entity, "Publication", INSERT, 3)));
historyRecords = orcidHistoryService.findAll(context);
assertThat(historyRecords, hasSize(3));
assertThat(historyRecords, contains(matches(history(owner, entity, 400, INSERT)),
matches(history(owner, entity, 400, INSERT)),
matches(history(owner, entity, 400, INSERT))));
assertThat(historyRecords, contains(matches(history(profileItem, entity, 400, INSERT)),
matches(history(profileItem, entity, 400, INSERT)),
matches(history(profileItem, entity, 400, INSERT))));
}
private Predicate<OrcidHistory> history(Item owner, Item entity, int status, OrcidOperation operation) {
return history -> owner.equals(history.getOwner())
private Predicate<OrcidHistory> history(Item profileItem, Item entity, int status, OrcidOperation operation) {
return history -> profileItem.equals(history.getProfileItem())
&& entity.equals(history.getEntity())
&& history.getStatus().equals(status)
&& operation == history.getOperation();
}
private Predicate<OrcidHistory> history(Item owner, int status, OrcidOperation operation) {
return history -> owner.equals(history.getOwner())
private Predicate<OrcidHistory> history(Item profileItem, int status, OrcidOperation operation) {
return history -> profileItem.equals(history.getProfileItem())
&& history.getStatus().equals(status)
&& operation == history.getOperation();
}
@@ -462,7 +462,8 @@ public class OrcidBulkPushIT extends AbstractIntegrationTestWithDatabase {
return handler;
}
private Item createOwnerItem(String orcid, EPerson owner, OrcidSynchronizationMode mode) throws Exception {
private Item createProfileItemItem(String orcid, EPerson owner, OrcidSynchronizationMode mode)
throws Exception {
Item item = ItemBuilder.createItem(context, profileCollection)
.withTitle("Test user")

View File

@@ -156,173 +156,6 @@ public class OrcidEntityFactoryServiceIT extends AbstractIntegrationTestWithData
}
@Test
public void testWorkWithFundingCreation() {
context.turnOffAuthorisationSystem();
Item publication = ItemBuilder.createItem(context, publications)
.withTitle("Test publication")
.withAuthor("Walter White")
.withIssueDate("2021-04-30")
.withType("Controlled Vocabulary for Resource Type Genres::text::book")
.withRelationFunding("Test funding")
.withRelationGrantno("123456")
.build();
context.restoreAuthSystemState();
Activity activity = entityFactoryService.createOrcidObject(context, publication);
assertThat(activity, instanceOf(Work.class));
Work work = (Work) activity;
List<ExternalID> externalIds = work.getExternalIdentifiers().getExternalIdentifier();
assertThat(externalIds, hasSize(1));
assertThat(externalIds, has(selfExternalId("handle", publication.getHandle())));
}
@Test
public void testWorkWithFundingWithoutGrantNumberCreation() {
context.turnOffAuthorisationSystem();
Item publication = ItemBuilder.createItem(context, publications)
.withTitle("Test publication")
.withAuthor("Walter White")
.withIssueDate("2021-04-30")
.withType("Controlled Vocabulary for Resource Type Genres::text::book")
.withRelationFunding("Test funding")
.build();
context.restoreAuthSystemState();
Activity activity = entityFactoryService.createOrcidObject(context, publication);
assertThat(activity, instanceOf(Work.class));
Work work = (Work) activity;
List<ExternalID> externalIds = work.getExternalIdentifiers().getExternalIdentifier();
assertThat(externalIds, hasSize(1));
assertThat(externalIds, has(selfExternalId("handle", publication.getHandle())));
}
@Test
public void testWorkWithFundingWithGrantNumberPlaceholderCreation() {
context.turnOffAuthorisationSystem();
Item publication = ItemBuilder.createItem(context, publications)
.withTitle("Test publication")
.withAuthor("Walter White")
.withIssueDate("2021-04-30")
.withType("Controlled Vocabulary for Resource Type Genres::text::book")
.withRelationFunding("Test funding")
.build();
context.restoreAuthSystemState();
Activity activity = entityFactoryService.createOrcidObject(context, publication);
assertThat(activity, instanceOf(Work.class));
Work work = (Work) activity;
List<ExternalID> externalIds = work.getExternalIdentifiers().getExternalIdentifier();
assertThat(externalIds, hasSize(1));
assertThat(externalIds, has(selfExternalId("handle", publication.getHandle())));
}
@Test
public void testWorkWithFundingEntityWithoutGrantNumberCreation() {
context.turnOffAuthorisationSystem();
Item funding = ItemBuilder.createItem(context, publications)
.withTitle("Test funding")
.build();
Item publication = ItemBuilder.createItem(context, publications)
.withTitle("Test publication")
.withAuthor("Walter White")
.withIssueDate("2021-04-30")
.withType("Controlled Vocabulary for Resource Type Genres::text::book")
.withRelationFunding("Test funding", funding.getID().toString())
.withRelationGrantno("123456")
.build();
context.restoreAuthSystemState();
Activity activity = entityFactoryService.createOrcidObject(context, publication);
assertThat(activity, instanceOf(Work.class));
Work work = (Work) activity;
List<ExternalID> externalIds = work.getExternalIdentifiers().getExternalIdentifier();
assertThat(externalIds, hasSize(1));
assertThat(externalIds, has(selfExternalId("handle", publication.getHandle())));
}
@Test
public void testWorkWithFundingEntityWithGrantNumberCreation() {
context.turnOffAuthorisationSystem();
Item funding = ItemBuilder.createItem(context, publications)
.withHandle("123456789/0001")
.withTitle("Test funding")
.withFundingIdentifier("987654")
.build();
Item publication = ItemBuilder.createItem(context, publications)
.withTitle("Test publication")
.withAuthor("Walter White")
.withIssueDate("2021-04-30")
.withType("Controlled Vocabulary for Resource Type Genres::text::book")
.withRelationFunding("Test funding", funding.getID().toString())
.withRelationGrantno("123456")
.build();
context.restoreAuthSystemState();
Activity activity = entityFactoryService.createOrcidObject(context, publication);
assertThat(activity, instanceOf(Work.class));
Work work = (Work) activity;
List<ExternalID> externalIds = work.getExternalIdentifiers().getExternalIdentifier();
assertThat(externalIds, hasSize(1));
assertThat(externalIds, has(selfExternalId("handle", publication.getHandle())));
}
@Test
public void testWorkWithFundingEntityWithGrantNumberAndUrlCreation() {
context.turnOffAuthorisationSystem();
Item funding = ItemBuilder.createItem(context, publications)
.withHandle("123456789/0001")
.withTitle("Test funding")
.withFundingIdentifier("987654")
.build();
Item publication = ItemBuilder.createItem(context, publications)
.withTitle("Test publication")
.withAuthor("Walter White")
.withIssueDate("2021-04-30")
.withType("Controlled Vocabulary for Resource Type Genres::text::book")
.withRelationFunding("Test funding", funding.getID().toString())
.withRelationGrantno("123456")
.build();
context.restoreAuthSystemState();
Activity activity = entityFactoryService.createOrcidObject(context, publication);
assertThat(activity, instanceOf(Work.class));
Work work = (Work) activity;
List<ExternalID> externalIds = work.getExternalIdentifiers().getExternalIdentifier();
assertThat(externalIds, hasSize(1));
assertThat(externalIds, has(selfExternalId("handle", publication.getHandle())));
}
@Test
public void testEmptyWorkWithUnknownTypeCreation() {

View File

@@ -71,28 +71,28 @@ public class PlainMetadataSignatureGeneratorIT extends AbstractIntegrationTestWi
.withTitle("Item title")
.withIssueDate("2020-01-01")
.withAuthor("Jesse Pinkman")
.withAuthorAffiliation("Affiliation")
.withEditor("Editor")
.build();
context.restoreAuthSystemState();
MetadataValue author = getMetadata(item, "dc.contributor.author", 0);
MetadataValue affiliation = getMetadata(item, "oairecerif.author.affiliation", 0);
MetadataValue editor = getMetadata(item, "dc.contributor.editor", 0);
String signature = generator.generate(context, List.of(author, affiliation));
String signature = generator.generate(context, List.of(author, editor));
assertThat(signature, notNullValue());
String expectedSignature = "dc.contributor.author::Jesse Pinkman§§"
+ "oairecerif.author.affiliation::Affiliation";
+ "dc.contributor.editor::Editor";
assertThat(signature, equalTo(expectedSignature));
String anotherSignature = generator.generate(context, List.of(affiliation, author));
String anotherSignature = generator.generate(context, List.of(editor, author));
assertThat(anotherSignature, equalTo(signature));
List<MetadataValue> metadataValues = generator.findBySignature(context, item, signature);
assertThat(metadataValues, hasSize(2));
assertThat(metadataValues, containsInAnyOrder(author, affiliation));
assertThat(metadataValues, containsInAnyOrder(author, editor));
}

View File

@@ -43,15 +43,15 @@ public class OrcidHistoryBuilder extends AbstractBuilder<OrcidHistory, OrcidHis
delete(orcidHistory);
}
public static OrcidHistoryBuilder createOrcidHistory(Context context, Item owner, Item entity) {
public static OrcidHistoryBuilder createOrcidHistory(Context context, Item profileItem, Item entity) {
OrcidHistoryBuilder builder = new OrcidHistoryBuilder(context);
return builder.create(context, owner, entity);
return builder.create(context, profileItem, entity);
}
private OrcidHistoryBuilder create(Context context, Item owner, Item entity) {
private OrcidHistoryBuilder create(Context context, Item profileItem, Item entity) {
try {
this.context = context;
this.orcidHistory = getService().create(context, owner, entity);
this.orcidHistory = getService().create(context, profileItem, entity);
} catch (Exception e) {
log.error("Error in OrcidHistoryBuilder.create(..), error: ", e);
}

View File

@@ -39,47 +39,47 @@ public class OrcidQueueBuilder extends AbstractBuilder<OrcidQueue, OrcidQueueSe
delete(orcidQueue);
}
public static OrcidQueueBuilder createOrcidQueue(Context context, Item owner, Item entity) {
public static OrcidQueueBuilder createOrcidQueue(Context context, Item profileItem, Item entity) {
OrcidQueueBuilder builder = new OrcidQueueBuilder(context);
return builder.createEntityInsertionRecord(context, owner, entity);
return builder.createEntityInsertionRecord(context, profileItem, entity);
}
public static OrcidQueueBuilder createOrcidQueue(Context context, Item owner, Item entity, String putCode) {
public static OrcidQueueBuilder createOrcidQueue(Context context, Item profileItem, Item entity, String putCode) {
OrcidQueueBuilder builder = new OrcidQueueBuilder(context);
return builder.createEntityUpdateRecord(context, owner, entity, putCode);
return builder.createEntityUpdateRecord(context, profileItem, entity, putCode);
}
public static OrcidQueueBuilder createOrcidQueue(Context context, Item owner, String description,
public static OrcidQueueBuilder createOrcidQueue(Context context, Item profileItem, String description,
String type, String putCode) {
OrcidQueueBuilder builder = new OrcidQueueBuilder(context);
return builder.createEntityDeletionRecord(context, owner, description, type, putCode);
return builder.createEntityDeletionRecord(context, profileItem, description, type, putCode);
}
private OrcidQueueBuilder createEntityDeletionRecord(Context context, Item owner,
private OrcidQueueBuilder createEntityDeletionRecord(Context context, Item profileItem,
String description, String type, String putCode) {
try {
this.context = context;
this.orcidQueue = getService().createEntityDeletionRecord(context, owner, description, type, putCode);
this.orcidQueue = getService().createEntityDeletionRecord(context, profileItem, description, type, putCode);
} catch (Exception e) {
throw new RuntimeException(e);
}
return this;
}
private OrcidQueueBuilder createEntityUpdateRecord(Context context, Item owner, Item entity, String putCode) {
private OrcidQueueBuilder createEntityUpdateRecord(Context context, Item profileItem, Item entity, String putCode) {
try {
this.context = context;
this.orcidQueue = getService().createEntityUpdateRecord(context, owner, entity, putCode);
this.orcidQueue = getService().createEntityUpdateRecord(context, profileItem, entity, putCode);
} catch (Exception e) {
throw new RuntimeException(e);
}
return this;
}
private OrcidQueueBuilder createEntityInsertionRecord(Context context, Item owner, Item entity) {
private OrcidQueueBuilder createEntityInsertionRecord(Context context, Item profileItem, Item entity) {
try {
this.context = context;
this.orcidQueue = getService().createEntityInsertionRecord(context, owner, entity);
this.orcidQueue = getService().createEntityInsertionRecord(context, profileItem, entity);
} catch (Exception e) {
throw new RuntimeException(e);
}

View File

@@ -586,7 +586,7 @@ public class ItemTest extends AbstractDSpaceObjectTest {
String schema = "dc";
String element = "contributor";
String qualifier = "editor";
String qualifier = "author";
String lang = Item.ANY;
List<String> values = Arrays.asList("value0", "value1");
List<String> authorities = Arrays.asList("auth0", "auth2");

View File

@@ -25,7 +25,7 @@ public class OrcidHistoryRestConverter implements DSpaceConverter<OrcidHistory,
public OrcidHistoryRest convert(OrcidHistory modelObject, Projection projection) {
OrcidHistoryRest rest = new OrcidHistoryRest();
rest.setId(modelObject.getID());
rest.setOwnerId(modelObject.getOwner().getID());
rest.setProfileItemId(modelObject.getProfileItem().getID());
rest.setEntityId(modelObject.getEntity() != null ? modelObject.getEntity().getID() : null);
rest.setResponseMessage(modelObject.getResponseMessage());
rest.setStatus(modelObject.getStatus());

View File

@@ -32,7 +32,7 @@ public class OrcidQueueRestConverter implements DSpaceConverter<OrcidQueue, Orci
rest.setDescription(orcidQueue.getDescription());
rest.setRecordType(orcidQueue.getRecordType());
rest.setId(orcidQueue.getID());
rest.setOwnerId(orcidQueue.getOwner().getID());
rest.setProfileItemId(orcidQueue.getProfileItem().getID());
rest.setOperation(orcidQueue.getOperation() != null ? orcidQueue.getOperation().name() : null);
rest.setProjection(projection);

View File

@@ -35,12 +35,12 @@ public class OrcidQueueHalLinkFactory extends HalLinkFactory<OrcidQueueResource,
throws Exception {
OrcidQueueRest orcidQueueRest = halResource.getContent();
if (orcidQueueRest.getOwnerId() != null) {
if (orcidQueueRest.getProfileItemId() != null) {
UriComponentsBuilder uriComponentsBuilder = linkTo(getMethodOn(ItemRest.CATEGORY, ItemRest.NAME)
.findRel(null, null, ItemRest.CATEGORY, English.plural(ItemRest.NAME),
orcidQueueRest.getOwnerId(), "", null, null)).toUriComponentsBuilder();
orcidQueueRest.getProfileItemId(), "", null, null)).toUriComponentsBuilder();
String uribuilder = uriComponentsBuilder.build().toString();
list.add(buildLink("owner", uribuilder.substring(0, uribuilder.lastIndexOf("/"))));
list.add(buildLink("profileItem", uribuilder.substring(0, uribuilder.lastIndexOf("/"))));
}
if (orcidQueueRest.getEntityId() != null) {

View File

@@ -26,7 +26,7 @@ public class OrcidHistoryRest extends BaseObjectRest<Integer> {
public static final String CATEGORY = RestModel.EPERSON;
public static final String NAME = "orcidhistory";
private UUID ownerId;
private UUID profileItemId;
private UUID entityId;
@@ -56,12 +56,12 @@ public class OrcidHistoryRest extends BaseObjectRest<Integer> {
return RestResourceController.class;
}
public UUID getOwnerId() {
return ownerId;
public UUID getProfileItemId() {
return profileItemId;
}
public void setOwnerId(UUID ownerId) {
this.ownerId = ownerId;
public void setProfileItemId(UUID profileItemId) {
this.profileItemId = profileItemId;
}
public UUID getEntityId() {

View File

@@ -20,7 +20,7 @@ public class OrcidQueueRest extends BaseObjectRest<Integer> {
public static final String NAME = "orcidqueue";
public static final String PLURAL_NAME = "orcidqueues";
private UUID ownerId;
private UUID profileItemId;
private UUID entityId;
@@ -45,12 +45,12 @@ public class OrcidQueueRest extends BaseObjectRest<Integer> {
return RestResourceController.class;
}
public UUID getOwnerId() {
return ownerId;
public UUID getProfileItemId() {
return profileItemId;
}
public void setOwnerId(UUID ownerId) {
this.ownerId = ownerId;
public void setProfileItemId(UUID profileItemId) {
this.profileItemId = profileItemId;
}
public UUID getEntityId() {

View File

@@ -78,17 +78,17 @@ public class OrcidQueueRestRepository extends DSpaceRestRepository<OrcidQueueRes
}
}
@SearchRestMethod(name = "findByOwner")
@PreAuthorize("hasPermission(#ownerId, 'ORCID_QUEUE_SEARCH', 'READ')")
public Page<OrcidQueueRest> findByOwnerId(@Parameter(value = "ownerId", required = true) String ownerId,
Pageable pageable) {
@SearchRestMethod(name = "findByProfileItem")
@PreAuthorize("hasPermission(#profileItemId, 'ORCID_QUEUE_SEARCH', 'READ')")
public Page<OrcidQueueRest> findByProfileItemId(
@Parameter(value = "profileItemId", required = true) String profileItemId, Pageable pageable) {
Context context = obtainContext();
try {
UUID id = UUID.fromString(ownerId);
List<OrcidQueue> result = orcidQueueService.findByOwnerId(context, id, pageable.getPageSize(),
UUID id = UUID.fromString(profileItemId);
List<OrcidQueue> result = orcidQueueService.findByProfileItemId(context, id, pageable.getPageSize(),
toIntExact(pageable.getOffset()));
long totalCount = orcidQueueService.countByOwnerId(context, id);
long totalCount = orcidQueueService.countByProfileItemId(context, id);
return converter.toRestPage(result, pageable, totalCount, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);

View File

@@ -88,7 +88,7 @@ public class OrcidHistorySendToOrcidRestPermissionEvaluatorPlugin extends RestOb
private boolean hasAccess(Context context, EPerson currentUser, OrcidQueue orcidQueue) {
if (orcidQueue != null) {
List<MetadataValue> value = itemService.getMetadata(orcidQueue.getOwner(),
List<MetadataValue> value = itemService.getMetadata(orcidQueue.getProfileItem(),
"dspace", "object", "owner", null);
if (value.get(0).getAuthority().equals(currentUser.getID().toString())) {
return true;

View File

@@ -87,12 +87,12 @@ public class OrcidQueueAndHistoryRestPermissionEvaluatorPlugin extends RestObjec
try {
Item owner = findOwner(context, orcidObjectId, isOrcidQueueRecord);
if (owner == null) {
Item profileItem = findProfileItem(context, orcidObjectId, isOrcidQueueRecord);
if (profileItem == null) {
return true;
}
return itemService.getMetadata(owner, "dspace", "object", "owner", Item.ANY).stream()
return itemService.getMetadata(profileItem, "dspace", "object", "owner", Item.ANY).stream()
.map(metadataValue -> metadataValue.getAuthority())
.anyMatch(authority -> currentUser.getID().toString().equals(authority));
@@ -103,13 +103,14 @@ public class OrcidQueueAndHistoryRestPermissionEvaluatorPlugin extends RestObjec
return false;
}
private Item findOwner(Context context, Integer orcidObjectId, boolean isOrcidQueueRecord) throws SQLException {
private Item findProfileItem(Context context, Integer orcidObjectId, boolean isOrcidQueueRecord)
throws SQLException {
if (isOrcidQueueRecord) {
OrcidQueue orcidQueue = orcidQueueService.find(context, orcidObjectId);
return orcidQueue != null ? orcidQueue.getOwner() : null;
return orcidQueue != null ? orcidQueue.getProfileItem() : null;
} else {
OrcidHistory orcidHistory = orcidHistoryService.find(context, orcidObjectId);
return orcidHistory != null ? orcidHistory.getOwner() : null;
return orcidHistory != null ? orcidHistory.getProfileItem() : null;
}
}

View File

@@ -2300,7 +2300,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
context.restoreAuthSystemState();
// no preferences configured, so no orcid queue records created
assertThat(orcidQueueService.findByOwnerId(context, profileItemId), empty());
assertThat(orcidQueueService.findByProfileItemId(context, profileItemId), empty());
String authToken = getAuthToken(ePerson.getEmail(), password);
@@ -2309,7 +2309,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk());
List<OrcidQueue> queueRecords = orcidQueueService.findByOwnerId(context, profileItemId);
List<OrcidQueue> queueRecords = orcidQueueService.findByProfileItemId(context, profileItemId);
assertThat(queueRecords, hasSize(1));
assertThat(queueRecords, has(orcidQueueRecordWithEntity(publication)));
@@ -2318,7 +2318,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk());
queueRecords = orcidQueueService.findByOwnerId(context, profileItemId);
queueRecords = orcidQueueService.findByProfileItemId(context, profileItemId);
assertThat(queueRecords, hasSize(3));
assertThat(queueRecords, has(orcidQueueRecordWithEntity(publication)));
assertThat(queueRecords, has(orcidQueueRecordWithEntity(firstProject)));
@@ -2329,7 +2329,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk());
queueRecords = orcidQueueService.findByOwnerId(context, profileItemId);
queueRecords = orcidQueueService.findByProfileItemId(context, profileItemId);
assertThat(queueRecords, hasSize(2));
assertThat(queueRecords, has(orcidQueueRecordWithEntity(firstProject)));
assertThat(queueRecords, has(orcidQueueRecordWithEntity(secondProject)));
@@ -2339,7 +2339,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk());
assertThat(orcidQueueService.findByOwnerId(context, profileItemId), empty());
assertThat(orcidQueueService.findByProfileItemId(context, profileItemId), empty());
}

View File

@@ -28,7 +28,7 @@ public class OrcidHistoryMatcher {
String responseMessage) {
return allOf(
hasJsonPath("$.id", is(orcidHistory.getID())),
hasJsonPath("$.ownerId", is(orcidHistory.getOwner().getID().toString())),
hasJsonPath("$.profileItemId", is(orcidHistory.getProfileItem().getID().toString())),
hasJsonPath("$.entityId", is(orcidHistory.getEntity().getID().toString())),
hasJsonPath("$.status", is(status)),
hasJsonPath("$.putCode", is(putCode)),

View File

@@ -30,7 +30,7 @@ public class OrcidQueueMatcher {
Item entity = orcidQueue.getEntity();
return allOf(
hasJsonPath("$.id", is(orcidQueue.getID())),
hasJsonPath("$.ownerId", is(orcidQueue.getOwner().getID().toString())),
hasJsonPath("$.profileItemId", is(orcidQueue.getProfileItem().getID().toString())),
hasJsonPath("$.entityId", entity != null ? is(entity.getID().toString()) : nullValue()),
hasJsonPath("$.description", is(orcidQueue.getDescription())),
hasJsonPath("$.recordType", is(orcidQueue.getRecordType())),

View File

@@ -291,7 +291,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(publication.getID().toString())),
hasJsonPath("$.status", is(201)),
hasJsonPath("$.putCode", is("12345")),
@@ -348,7 +348,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(publication.getID().toString())),
hasJsonPath("$.responseMessage", is("Invalid resource")),
hasJsonPath("$.status", is(400)),
@@ -396,7 +396,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(publication.getID().toString())),
hasJsonPath("$.responseMessage", is("GENERIC ERROR")),
hasJsonPath("$.status", is(500)),
@@ -445,7 +445,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(publication.getID().toString())),
hasJsonPath("$.status", is(200)),
hasJsonPath("$.putCode", is("12345")),
@@ -503,7 +503,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(publication.getID().toString())),
hasJsonPath("$.status", is(201)),
hasJsonPath("$.putCode", is("12345")),
@@ -555,7 +555,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", nullValue()),
hasJsonPath("$.status", is(204)),
hasJsonPath("$.putCode", nullValue()),
@@ -597,7 +597,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", nullValue()),
hasJsonPath("$.status", is(204)),
hasJsonPath("$.putCode", nullValue()),
@@ -644,7 +644,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(profile.getID().toString())),
hasJsonPath("$.status", is(201)),
hasJsonPath("$.putCode", is("12345")),
@@ -702,7 +702,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(profile.getID().toString())),
hasJsonPath("$.status", is(204)),
hasJsonPath("$.putCode", nullValue()),
@@ -782,7 +782,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(funding.getID().toString())),
hasJsonPath("$.status", is(201)),
hasJsonPath("$.putCode", is("12345")),
@@ -873,7 +873,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(funding.getID().toString())),
hasJsonPath("$.responseMessage", is("Invalid resource")),
hasJsonPath("$.status", is(400)),
@@ -955,7 +955,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(funding.getID().toString())),
hasJsonPath("$.responseMessage", is("GENERIC ERROR")),
hasJsonPath("$.status", is(500)),
@@ -1038,7 +1038,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", is(funding.getID().toString())),
hasJsonPath("$.status", is(200)),
hasJsonPath("$.putCode", is("12345")),
@@ -1090,7 +1090,7 @@ public class OrcidHistoryRestRepositoryIT extends AbstractControllerIntegrationT
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.id", is(idRef.get())),
hasJsonPath("$.ownerId", is(profile.getID().toString())),
hasJsonPath("$.profileItemId", is(profile.getID().toString())),
hasJsonPath("$.entityId", nullValue()),
hasJsonPath("$.status", is(204)),
hasJsonPath("$.putCode", nullValue()),

View File

@@ -50,7 +50,7 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
}
@Test
public void findByOwnerTest() throws Exception {
public void findByProfileItemTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson researcher = EPersonBuilder.createEPerson(context)
@@ -122,8 +122,8 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
String tokenResearcher = getAuthToken(researcher.getEmail(), password);
String tokenResearcher2 = getAuthToken(researcher2.getEmail(), password);
getClient(tokenResearcher).perform(get("/api/eperson/orcidqueue/search/findByOwner")
.param("ownerId", itemPerson.getID().toString()))
getClient(tokenResearcher).perform(get("/api/eperson/orcidqueue/search/findByProfileItem")
.param("profileItemId", itemPerson.getID().toString()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.orcidqueues", Matchers.containsInAnyOrder(
OrcidQueueMatcher.matchOrcidQueue(orcidQueue),
@@ -131,18 +131,18 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
)))
.andExpect(jsonPath("$.page.totalElements", is(2)));
getClient(tokenResearcher2).perform(get("/api/eperson/orcidqueue/search/findByOwner")
.param("ownerId", itemPerson2.getID().toString()))
getClient(tokenResearcher2).perform(get("/api/eperson/orcidqueue/search/findByProfileItem")
.param("profileItemId", itemPerson2.getID().toString()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.orcidqueues", Matchers.contains(
matchOrcidQueue(orcidQueue2)
)))
.andExpect(jsonPath("$.page.totalElements", is(1)))
.andExpect(jsonPath("$._links.self.href", Matchers
.containsString("/api/eperson/orcidqueue/search/findByOwner")));
.containsString("/api/eperson/orcidqueue/search/findByProfileItem")));
getClient(tokenAdmin).perform(get("/api/eperson/orcidqueue/search/findByOwner")
.param("ownerId", itemPerson.getID().toString()))
getClient(tokenAdmin).perform(get("/api/eperson/orcidqueue/search/findByProfileItem")
.param("profileItemId", itemPerson.getID().toString()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.orcidqueues", Matchers.containsInAnyOrder(
OrcidQueueMatcher.matchOrcidQueue(orcidQueue),
@@ -152,7 +152,7 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
}
@Test
public void findByOwnerForbiddenTest() throws Exception {
public void findByProfileItemForbiddenTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson researcher = EPersonBuilder.createEPerson(context)
@@ -213,13 +213,13 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
context.restoreAuthSystemState();
String tokenResearcher2 = getAuthToken(researcher2.getEmail(), password);
getClient(tokenResearcher2).perform(get("/api/eperson/orcidqueue/search/findByOwner")
.param("ownerId", itemPerson.getID().toString()))
getClient(tokenResearcher2).perform(get("/api/eperson/orcidqueue/search/findByProfileItem")
.param("profileItemId", itemPerson.getID().toString()))
.andExpect(status().isForbidden());
}
@Test
public void findByOwnerUnauthorizedTest() throws Exception {
public void findByProfileItemUnauthorizedTest() throws Exception {
context.turnOffAuthorisationSystem();
EPerson researcher = EPersonBuilder.createEPerson(context)
@@ -259,8 +259,8 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
context.restoreAuthSystemState();
getClient().perform(get("/api/eperson/orcidqueue/search/findByOwner")
.param("ownerId", itemPerson.getID().toString()))
getClient().perform(get("/api/eperson/orcidqueue/search/findByProfileItem")
.param("profileItemId", itemPerson.getID().toString()))
.andExpect(status().isUnauthorized());
}
@@ -327,7 +327,7 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(jsonPath("$", is(matchOrcidQueue(orcidQueue))))
.andExpect(jsonPath("$._links.self.href", Matchers
.containsString("/api/eperson/orcidqueues/" + orcidQueue.getID())))
.andExpect(jsonPath("$._links.owner.href", Matchers
.andExpect(jsonPath("$._links.profileItem.href", Matchers
.containsString("/api/core/items/" + itemPerson1.getID())))
.andExpect(jsonPath("$._links.entity.href", Matchers
.containsString("/api/core/items/" + itemPublication.getID())));
@@ -337,7 +337,7 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(jsonPath("$", is(matchOrcidQueue(orcidQueue2))))
.andExpect(jsonPath("$._links.self.href", Matchers
.containsString("/api/eperson/orcidqueues/" + orcidQueue2.getID())))
.andExpect(jsonPath("$._links.owner.href", Matchers
.andExpect(jsonPath("$._links.profileItem.href", Matchers
.containsString("/api/core/items/" + itemPerson2.getID())))
.andExpect(jsonPath("$._links.entity.href", Matchers
.containsString("/api/core/items/" + itemPublication2.getID())));
@@ -377,7 +377,7 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(jsonPath("$", is(matchOrcidQueue(orcidQueue))))
.andExpect(jsonPath("$._links.self.href", containsString("/api/eperson/orcidqueues/" + orcidQueue.getID())))
.andExpect(jsonPath("$._links.owner.href", containsString("/api/core/items/" + itemPerson.getID())));
.andExpect(jsonPath("$._links.profileItem.href", containsString("/api/core/items/" + itemPerson.getID())));
}
@Test
@@ -591,7 +591,7 @@ public class OrcidQueueRestRepositoryIT extends AbstractControllerIntegrationTes
Item itemPerson1 = ItemBuilder.createItem(context, col1)
.withPersonIdentifierFirstName("Josiah")
.withPersonIdentifierLastName("Carberry")
.withDspaceObjectOwner(researcher.getFullName(), researcher.getID().toString())
.withDspaceObjectOwner(researcher.getFullName(), researcher.getID().toString())
.build();
itemService.addMetadata(context, itemPerson1, "person", "identifier", "orcid", "en", "0000-0002-1825-0097");

View File

@@ -1,8 +0,0 @@
en = en
es = es
de = de
fr = fr
it = it
ja = ja
zh = zh
tr = tr

View File

@@ -1,11 +0,0 @@
website = Other
data-set = Dataset
book = Book
book-chapter = Book chapter
conference-paper = Other
journal-article = Article
newspaper-article = Article
magazine-article = Article
patent = Other
report = Other
book-review = Other

View File

@@ -1570,7 +1570,6 @@ include = ${module_dir}/authentication-oidc.cfg
include = ${module_dir}/authentication-password.cfg
include = ${module_dir}/authentication-shibboleth.cfg
include = ${module_dir}/authentication-x509.cfg
include = ${module_dir}/authentication-orcid.cfg
include = ${module_dir}/authority.cfg
include = ${module_dir}/bulkedit.cfg
include = ${module_dir}/citation-page.cfg

View File

@@ -1,33 +0,0 @@
#------------------------------------------------------------------#
#--------------------ORCID GENERIC CONFIGURATIONS------------------#
#------------------------------------------------------------------#
# Configuration with which it is established which user can disconnect a profile from orcid (none, only the admin, only the owner or both).
# Allowed values are disabled, only_admin, only_owner or admin_and_owner
orcid.disconnection.allowed-users = admin_and_owner
#------------------------------------------------------------------#
#--------------------ORCID CLIENT CONFIGURATIONS-------------------#
#------------------------------------------------------------------#
# ORCID API (https://github.com/ORCID/ORCID-Source/tree/master/orcid-api-web#endpoints)
orcid.domain-url= https://sandbox.orcid.org
orcid.authorize-url = ${orcid.domain-url}/oauth/authorize
orcid.token-url = ${orcid.domain-url}/oauth/token
orcid.api-url = https://api.sandbox.orcid.org/v3.0
orcid.public-url = https://pub.sandbox.orcid.org/v3.0
orcid.redirect-url = ${dspace.server.url}/api/authn/orcid
# ORCID Credentials
# Your public or member API Credentials, see
# https://orcid.org/content/register-client-application-0
# https://info.orcid.org/register-a-client-application-sandbox-member-api/
orcid.application-client-id =
orcid.application-client-secret =
# The scopes to be granted by the user during the login on ORCID (see https://info.orcid.org/faq/what-is-an-oauth-scope-and-which-scopes-does-orcid-support/)
orcid.scope = /authenticate
orcid.scope = /read-limited
orcid.scope = /activities/update
orcid.scope = /person/update

View File

@@ -79,7 +79,7 @@ authority.minconfidence = ambiguous
# org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority
plugin.named.org.dspace.content.authority.ChoiceAuthority = \
org.dspace.content.authority.EPersonAuthority = EPersonAuthority
org.dspace.content.authority.EPersonAuthority = EPersonAuthority
# Configuration settings required for Researcher Profiles
# These settings ensure "dspace.object.owner" field are indexed by Authority Control

View File

@@ -1,4 +1,37 @@
#------------------------------------------------------------------#
#--------------------ORCID GENERIC CONFIGURATIONS------------------#
#------------------------------------------------------------------#
# Configuration with which it is established which user can disconnect a profile from orcid (none, only the admin, only the owner or both).
# Allowed values are disabled, only_admin, only_owner or admin_and_owner
orcid.disconnection.allowed-users = admin_and_owner
#------------------------------------------------------------------#
#--------------------ORCID CLIENT CONFIGURATIONS-------------------#
#------------------------------------------------------------------#
# ORCID API (https://github.com/ORCID/ORCID-Source/tree/master/orcid-api-web#endpoints)
orcid.domain-url= https://sandbox.orcid.org
orcid.authorize-url = ${orcid.domain-url}/oauth/authorize
orcid.token-url = ${orcid.domain-url}/oauth/token
orcid.api-url = https://api.sandbox.orcid.org/v3.0
orcid.public-url = https://pub.sandbox.orcid.org/v3.0
orcid.redirect-url = ${dspace.server.url}/api/authn/orcid
# ORCID Credentials
# Your public or member API Credentials, see
# https://orcid.org/content/register-client-application-0
# https://info.orcid.org/register-a-client-application-sandbox-member-api/
orcid.application-client-id =
orcid.application-client-secret =
# The scopes to be granted by the user during the login on ORCID (see https://info.orcid.org/faq/what-is-an-oauth-scope-and-which-scopes-does-orcid-support/)
orcid.scope = /authenticate
orcid.scope = /read-limited
orcid.scope = /activities/update
orcid.scope = /person/update
#------------------------------------------------------------------#
#--------------------ORCID MAPPING CONFIGURATIONS------------------#
#------------------------------------------------------------------#
@@ -91,6 +124,7 @@ orcid.validation.affiliation.enabled = true
orcid.validation.work.enabled = true
orcid.validation.funding.enabled = true
## Supported organization identifier sources
orcid.validation.organization.identifier-sources = RINGGOLD
orcid.validation.organization.identifier-sources = GRID
orcid.validation.organization.identifier-sources = FUNDREF
@@ -100,31 +134,5 @@ orcid.validation.organization.identifier-sources = LEI
#---------------------ORCID BULK SYNCHRONIZATION-------------------#
#------------------------------------------------------------------#
orcid.bulk-synchronization.max-attempts = 5
#------------------------------------------------------------------#
#--------------------ORCID EXTERNAL DATA MAPPING-------------------#
#------------------------------------------------------------------#
### Work (Publication) external-data.mapping ###
orcid.external-data.mapping.publication.title = dc.title
orcid.external-data.mapping.publication.description = dc.description.abstract
orcid.external-data.mapping.publication.issued-date = dc.date.issued
orcid.external-data.mapping.publication.language = dc.language.iso
orcid.external-data.mapping.publication.language.converter = mapConverterOrcidToDSpaceLanguageCode
orcid.external-data.mapping.publication.is-part-of = dc.relation.ispartof
orcid.external-data.mapping.publication.type = dc.type
orcid.external-data.mapping.publication.type.converter = mapConverterOrcidToDSpacePublicationType
##orcid.external-data.mapping.publication.contributors syntax is <metadatafield>::<role>
orcid.external-data.mapping.publication.contributors = dc.contributor.author::author
orcid.external-data.mapping.publication.contributors = dc.contributor.editor::editor
##orcid.external-data.mapping.publication.external-ids syntax is <metadatafield>::<type> or $simple-handle::<type>
##The full list of available external identifiers is available here https://pub.orcid.org/v3.0/identifiers
orcid.external-data.mapping.publication.external-ids = dc.identifier.doi::doi
orcid.external-data.mapping.publication.external-ids = dc.identifier.scopus::eid
orcid.external-data.mapping.publication.external-ids = dc.identifier.pmid::pmid
orcid.external-data.mapping.publication.external-ids = dc.identifier.isi::wosuid
orcid.external-data.mapping.publication.external-ids = dc.identifier.issn::issn
## Configuration for max attempts during ORCID batch synchronization
orcid.bulk-synchronization.max-attempts = 5

View File

@@ -271,6 +271,7 @@
<schema>dc</schema>
<element>identifier</element>
<qualifier>scopus</qualifier>
<scope_note>The scopus identifier</scope_note>
</dc-type>
<!-- Used by system: do not remove -->

View File

@@ -11,20 +11,6 @@
<namespace>https://www.openaire.eu/cerif-profile/1.1/</namespace>
</dc-schema>
<dc-type>
<schema>oairecerif</schema>
<element>author</element>
<qualifier>affiliation</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>editor</element>
<qualifier>affiliation</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>identifier</element>
@@ -32,47 +18,12 @@
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>affiliation</element>
<qualifier>orgunit</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>affiliation</element>
<qualifier>startDate</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>affiliation</element>
<qualifier>endDate</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>affiliation</element>
<qualifier>role</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>person</element>
<qualifier>gender</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
<element>person</element>
<qualifier>affiliation</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>oairecerif</schema>
@@ -207,26 +158,4 @@
<scope_note></scope_note>
</dc-type>
<!-- These below should be moved in the oairecerif schema -->
<dc-type>
<schema>dc</schema>
<element>relation</element>
<qualifier>project</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>dc</schema>
<element>relation</element>
<qualifier>funding</qualifier>
<scope_note></scope_note>
</dc-type>
<dc-type>
<schema>dc</schema>
<element>relation</element>
<qualifier>grantno</qualifier>
<scope_note></scope_note>
</dc-type>
</dspace-dc-types>

View File

@@ -78,6 +78,7 @@
<schema>organization</schema>
<element>identifier</element>
<qualifier>crossrefid</qualifier>
<scope_note>Crossref identifier</scope_note>
</dc-type>

View File

@@ -145,12 +145,14 @@
<schema>person</schema>
<element>name</element>
<qualifier>translated</qualifier>
<scope_note>Full name translation</scope_note>
</dc-type>
<dc-type>
<schema>person</schema>
<element>name</element>
<qualifier>variant</qualifier>
<scope_note>Full name variant</scope_note>
</dc-type>
</dspace-dc-types>

View File

@@ -89,6 +89,8 @@
<property name="disambiguatedOrganizationIdentifierFields" value="${orcid.mapping.organization.identifiers}" />
</bean>
<!-- Configuration of ORCID profile sections factory.
Each entry of sectionFactories must be an implementation of OrcidProfileSectionFactory.-->
<bean class="org.dspace.app.orcid.service.impl.OrcidProfileSectionFactoryServiceImpl">
<constructor-arg name="sectionFactories">
<list>
@@ -128,51 +130,25 @@
</bean>
<bean name="mapConverterDSpaceToOrcidPublicationType" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="mapConverter-dspace-to-orcid-publication-type.properties" />
<property name="converterNameFile" value="orcid/mapConverter-dspace-to-orcid-publication-type.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value="other"/>
</bean>
<bean name="mapConverterDSpaceToOrcidLanguageCode" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="mapConverter-dspace-to-orcid-language-code.properties" />
<property name="converterNameFile" value="orcid/mapConverter-dspace-to-orcid-language-code.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value=""/>
</bean>
<bean name="mapConverterDSpaceToOrcidFundingType" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="mapConverter-dspace-to-orcid-funding-type.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value="grant"/>
</bean>
<bean name="mapConverterDSpaceToOrcidAmountCurrency" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="mapConverter-dspace-to-orcid-amount-currency.properties" />
<property name="converterNameFile" value="orcid/mapConverter-dspace-to-orcid-funding-type.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value=""/>
</bean>
<bean id="orcidPublicationDataProviderFieldMapping" class="org.dspace.app.orcid.model.OrcidWorkFieldMapping" >
<property name="contributorFields" value="${orcid.external-data.mapping.publication.contributors}" />
<property name="externalIdentifierFields" value="${orcid.external-data.mapping.publication.external-ids}" />
<property name="publicationDateField" value="${orcid.external-data.mapping.publication.issued-date}" />
<property name="titleField" value="${orcid.external-data.mapping.publication.title}" />
<property name="journalTitleField" value="${orcid.external-data.mapping.publication.is-part-of}" />
<property name="shortDescriptionField" value="${orcid.external-data.mapping.publication.description}" />
<property name="languageField" value="${orcid.external-data.mapping.publication.language}" />
<property name="languageConverter" ref="${orcid.external-data.mapping.publication.language.converter}" />
<property name="typeField" value="${orcid.external-data.mapping.publication.type}" />
<property name="typeConverter" ref="${orcid.external-data.mapping.publication.type.converter}" />
</bean>
<bean name="mapConverterOrcidToDSpacePublicationType" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="mapConverter-orcid-to-dspace-publication-type.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value="Controlled Vocabulary for Resource Type Genres::other"/>
</bean>
<bean name="mapConverterOrcidToDSpaceLanguageCode" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="mapConverter-orcid-to-dspace-language-code.properties" />
<bean name="mapConverterDSpaceToOrcidAmountCurrency" class="org.dspace.util.SimpleMapConverter" init-method="init">
<property name="converterNameFile" value="orcid/mapConverter-dspace-to-orcid-amount-currency.properties" />
<property name="configurationService" ref="org.dspace.services.ConfigurationService" />
<property name="defaultValue" value=""/>
</bean>