Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Push selected publications to orcid #351

Open
wants to merge 25 commits into
base: dspace-cris-2023_02_x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a5164d3
orcid preferences based on hidden/selected relations
floriangantner Dec 6, 2022
7285e5b
fix checkstyle issues
floriangantner Dec 7, 2022
125297f
orcid preferences based on hidden/selected relations
floriangantner Dec 6, 2022
996c674
fix checkstyle issues
floriangantner Dec 7, 2022
ee529cd
Merge remote-tracking branch 'origin/dspace-cris-7-orcid-relpref' int…
floriangantner Jul 3, 2023
d4861ec
sql script in post migration transforming orcid publications and fund…
floriangantner Jul 3, 2023
86aee5a
Revert "sql script in post migration transforming orcid publications …
floriangantner Jul 3, 2023
9dd4406
fix build error from merge
floriangantner Jul 4, 2023
e61c941
fix checkstyle issue
floriangantner Jul 5, 2023
a819ea8
Merge branch 'dspace-cris-7' into dspace-cris-7-orcid-relpref
floriangantner Aug 17, 2023
26b58ae
delete orcid queues entries which should not be synchronized
floriangantner Aug 18, 2023
f096dbd
minor fixes on orcud queue und sync implementations
floriangantner Aug 18, 2023
6224aaa
Integration tests for orcid queue among relations
floriangantner Aug 18, 2023
fbec539
improve and align replacement of variable
floriangantner Aug 18, 2023
7b83615
Merge branch 'dspace-cris-7' into dspace-cris-7-orcid-relpref
floriangantner Aug 25, 2023
28cc884
refactor deletion of orcidqueue entries among relationships
floriangantner Aug 25, 2023
e7d4bc1
fix checkstyle
floriangantner Aug 25, 2023
6b9c478
enable config for funding
floriangantner Aug 25, 2023
b2fad1a
fix wrong config property breaking tests
floriangantner Aug 28, 2023
393eb44
Merge branch 'dspace-cris-7' into dspace-cris-7-orcid-relpref
floriangantner Oct 13, 2023
6920c38
use relationship approach for orcid sync setting
floriangantner Nov 9, 2023
d8c31e3
clear orcid queue before recalculating all option
floriangantner Dec 20, 2023
99b49ed
Merge tag 'dspace-cris-2023.02.02' into dspace-cris-7-orcid-relpref
floriangantner Feb 20, 2024
8f62449
fix integration test with orcidqueueconsumer
floriangantner Feb 20, 2024
f64f736
further IT for my_selected orcid sync option
floriangantner Mar 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2151,7 +2151,7 @@ private void createOrcidQueueRecordsToDeleteOnOrcid(Context context, Item entity

Map<Item, String> profileAndPutCodeMap = orcidHistoryService.findLastPutCodes(context, entity);
for (Item profile : profileAndPutCodeMap.keySet()) {
if (orcidSynchronizationService.isSynchronizationAllowed(profile, entity)) {
if (orcidSynchronizationService.isSynchronizationAllowed(context, profile, entity)) {
String putCode = profileAndPutCodeMap.get(profile);
String title = getMetadataFirstValue(entity, "dc", "title", null, Item.ANY);
orcidQueueService.createEntityDeletionRecord(context, profile, title, entityType, putCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.dspace.event.Event;
import org.dspace.orcid.OrcidHistory;
import org.dspace.orcid.OrcidOperation;
import org.dspace.orcid.OrcidQueue;
import org.dspace.orcid.factory.OrcidServiceFactory;
import org.dspace.orcid.model.OrcidEntityType;
import org.dspace.orcid.model.factory.OrcidProfileSectionFactory;
Expand Down Expand Up @@ -170,7 +171,20 @@ private void consumeEntity(Context context, Item entity) throws SQLException {
continue;
}

if (shouldNotBeSynchronized(relatedItem, entity) || isAlreadyQueued(context, relatedItem, entity)) {
if (shouldNotBeSynchronized(context, relatedItem, entity) ||
isAlreadyQueued(context, relatedItem, entity)) {
// delete queue entries which are queued and relate on relationships,
// but where the relation does not exist anymore.
// Using the shouldNotBySynchonized might not be actual, because the solr
// might be behind the database state
if (isAlreadyQueued(context, relatedItem, entity)
&& isSyncSettingsBasedOnRelationshipCriteriaNotValid(context, relatedItem, entity)) {
List<OrcidQueue> queueentries =
orcidQueueService.findByProfileItemAndEntity(context, relatedItem, entity);
for (OrcidQueue queueentry : queueentries) {
orcidQueueService.delete(context, queueentry);
}
}
continue;
}

Expand Down Expand Up @@ -305,8 +319,14 @@ private boolean hasNotOrcidAccessToken(Context context, Item profileItemItem) {
return orcidTokenService.findByProfileItem(context, profileItemItem) == null;
}

private boolean shouldNotBeSynchronized(Item profileItem, Item entity) {
return !orcidSynchronizationService.isSynchronizationAllowed(profileItem, entity);
private boolean shouldNotBeSynchronized(Context context, Item profileItem, Item entity) {
return !orcidSynchronizationService.isSynchronizationAllowed(context, profileItem, entity);
}

private boolean isSyncSettingsBasedOnRelationshipCriteriaNotValid(
Context context, Item profileItem, Item entity) {
return orcidSynchronizationService.
isSyncSettingsBasedOnRelationshipCriteriaNotValid(context, profileItem, entity);
}

private boolean isNotProfileItem(Item profileItemItem) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import org.dspace.profile.OrcidSynchronizationMode;

/**
* Service that handle the the syncronization between a DSpace profile and the
* Service that handle the syncronization between a DSpace profile and the
* relative ORCID profile, if any.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
Expand Down Expand Up @@ -117,10 +117,10 @@ public boolean setSynchronizationMode(Context context, Item profile, OrcidSynchr
*
* @param profile the researcher profile item
* @param item the entity type to check
* @return true if the given entity type can be synchronize with ORCID,
* @return true if the given entity type can be synchronized with ORCID,
* false otherwise
*/
public boolean isSynchronizationAllowed(Item profile, Item item);
public boolean isSynchronizationAllowed(Context context, Item profile, Item item);

/**
* Returns the ORCID synchronization mode configured for the given profile item.
Expand All @@ -130,6 +130,18 @@ public boolean setSynchronizationMode(Context context, Item profile, OrcidSynchr
*/
Optional<OrcidSynchronizationMode> getSynchronizationMode(Item profile);

/**
* Check if the current sync setting for the items is related to some relationship.
* And if so than check if the relationship criteria is not valid.
*
* @param profile the researcher profile item
* @param item the entity type to check
* @return true if the given entity type is bases on relationship
* false otherwise
*/
boolean isSyncSettingsBasedOnRelationshipCriteriaNotValid(Context context, Item profile, Item item);


/**
* Returns the ORCID synchronization preference related to the given entity type
* configured for the given profile item.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
package org.dspace.orcid.service.impl;

import static org.apache.commons.lang3.ArrayUtils.contains;
import static org.dspace.profile.OrcidEntitySyncPreference.DISABLED;
import static org.dspace.profile.OrcidEntitySyncPreference.MINE;
import static org.dspace.profile.OrcidEntitySyncPreference.MY_SELECTED;

import java.sql.SQLException;
import java.util.Collections;
Expand Down Expand Up @@ -220,9 +223,27 @@ public void recalculateOrcidQueue(Context context, Item profileItem, OrcidEntity
OrcidEntitySyncPreference preference) throws SQLException {

String entityType = orcidEntityType.getEntityType();
if (preference == OrcidEntitySyncPreference.DISABLED) {
if (preference == DISABLED) {
deleteByProfileItemAndRecordType(context, profileItem, entityType);
} else if (preference == MY_SELECTED || preference == MINE) {
// delete existing queue
deleteByProfileItemAndRecordType(context, profileItem, entityType);
// add additional filterquery
String relationname =
configurationService.getProperty("orcid.relation." + entityType + "." + preference.name());
boolean exclusion = configurationService.getBooleanProperty("orcid.relation."
+ entityType + "." + preference.name() + ".exclusion", false);
if (StringUtils.isBlank(relationname)) {
return;
}
Iterator<Item> entities;
entities = findAllRelationShipEntitiesLinkableWith(context, profileItem, entityType, relationname,
exclusion);
while (entities.hasNext()) {
create(context, profileItem, entities.next());
}
} else {
deleteByProfileItemAndRecordType(context, profileItem, entityType);
Iterator<Item> entities = findAllEntitiesLinkableWith(context, profileItem, entityType);
while (entities.hasNext()) {
create(context, profileItem, entities.next());
Expand Down Expand Up @@ -254,6 +275,40 @@ private Iterator<Item> findAllEntitiesLinkableWith(Context context, Item owner,

}

private Iterator<Item> findAllRelationShipEntitiesLinkableWith(
Context context, Item owner, String entityType, String filterrelationname, boolean exclusion) {

String ownerType = itemService.getEntityType(owner);

String query = choiceAuthorityService.getAuthorityControlledFieldsByEntityType(ownerType).stream()
.map(metadataField -> metadataField.replaceAll("_", "."))
.filter(metadataField -> shouldNotBeIgnoredForOrcid(metadataField))
.map(metadataField -> metadataField + "_allauthority: \"" + owner.getID().toString() + "\"")
.collect(Collectors.joining(" OR "));

if (StringUtils.isEmpty(query)) {
return Collections.emptyIterator();
}

StringBuilder sb = new StringBuilder();
if (exclusion) {
sb.append("-");
}
sb.append("relation." + filterrelationname + ":");
sb.append(owner.getID().toString());

DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.addDSpaceObjectFilter(IndexableItem.TYPE);
discoverQuery.addFilterQueries(query);
discoverQuery.addFilterQueries("search.entitytype:" + entityType);

discoverQuery.addFilterQueries(sb.toString());

return new DiscoverResultItemIterator(context, discoverQuery);

}


private boolean shouldNotBeIgnoredForOrcid(String metadataField) {
return !contains(configurationService.getArrayProperty("orcid.linkable-metadata-fields.ignore"), metadataField);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import static org.apache.commons.lang3.EnumUtils.isValidEnum;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.dspace.content.Item.ANY;
import static org.dspace.profile.OrcidEntitySyncPreference.DISABLED;

import java.sql.SQLException;
import java.util.HashSet;
Expand All @@ -30,6 +29,7 @@
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.RelationshipService;
import org.dspace.core.Context;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResultItemIterator;
Expand Down Expand Up @@ -81,6 +81,9 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
@Autowired
private ResearcherProfileService researcherProfileService;

@Autowired
private RelationshipService relationshipService;

@Override
public void linkProfile(Context context, Item profile, OrcidTokenResponseDTO token) throws SQLException {

Expand Down Expand Up @@ -181,7 +184,7 @@ public boolean setSynchronizationMode(Context context, Item profile, OrcidSynchr
}

@Override
public boolean isSynchronizationAllowed(Item profile, Item item) {
public boolean isSynchronizationAllowed(Context context, Item profile, Item item) {

if (isOrcidSynchronizationDisabled()) {
return false;
Expand All @@ -193,9 +196,41 @@ public boolean isSynchronizationAllowed(Item profile, Item item) {
}

if (OrcidEntityType.isValidEntityType(entityType)) {
return getEntityPreference(profile, OrcidEntityType.fromEntityType(entityType))
.filter(pref -> pref != DISABLED)
.isPresent();
Optional<OrcidEntitySyncPreference> option;
option = getEntityPreference(profile, OrcidEntityType.fromEntityType(entityType));
if (option.isPresent()) {
try {
switch (option.get()) {
case DISABLED:
return false;
case ALL:
return true;
case MINE:
case MY_SELECTED:
String relationname = configurationService.getProperty("orcid.relation." + entityType + "."
+ option.get().name());
if (isBlank(relationname)) {
return false;
}
if (configurationService.getBooleanProperty("orcid.relation." + entityType + "."
+ option.get().name() + ".exclusion", false)) {
//check if no relationship exists between profile and item (e.g. MINE)
return relationShipMatchForOrcidSync(context, profile, item, relationname, false);
} else {
//check, if any relationship exists between profile and item(e.g. MY_SELECTED)

return relationShipMatchForOrcidSync(context, profile, item, relationname, true);

}
default:
return false;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
} else {
return false;
}
}

if (entityType.equals(researcherProfileService.getProfileType())) {
Expand All @@ -206,6 +241,58 @@ public boolean isSynchronizationAllowed(Item profile, Item item) {

}

@Override
public boolean isSyncSettingsBasedOnRelationshipCriteriaNotValid(Context context, Item profile, Item item) {
String entityType = itemService.getEntityTypeLabel(item);
if (entityType == null) {
return false;
}
Optional<OrcidEntitySyncPreference> option =
getEntityPreference(profile, OrcidEntityType.fromEntityType(entityType));
if (option.isPresent()) {
try {
switch (option.get()) {
case MINE:
case MY_SELECTED:
String relationname = configurationService.getProperty("orcid.relation." + entityType + "."
+ option.get().name());
if (isBlank(relationname)) {
return false;
}

//because we check the criteria is not valid we have to check the opposite
if (configurationService.getBooleanProperty("orcid.relation." + entityType + "."
+ option.get().name() + ".exclusion", false)) {
//check, if any relationship exists between profile and item (e.g. MINE)
return relationShipMatchForOrcidSync(context, profile, item, relationname, true);
} else {
//check if none relationship exist between profile and item (e.g. MY_SELECT)
return relationShipMatchForOrcidSync(context, profile, item, relationname, false);
}

default:
return false;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return false;
}

protected boolean relationShipMatchForOrcidSync(Context context, Item profile, Item item, String relationname,
boolean any) throws SQLException {
if (any) {
return relationshipService.findByItem(context, profile).stream().anyMatch(relationship ->
relationship.getLeftItem().getID().toString().equals(item.getID().toString()) &&
relationship.getLeftwardValue().contentEquals(relationname));
} else {
return relationshipService.findByItem(context, profile).stream().noneMatch(relationship ->
relationship.getLeftItem().getID().toString().equals(item.getID().toString()) &&
relationship.getLeftwardValue().contentEquals(relationname));
}
}

@Override
public Optional<OrcidSynchronizationMode> getSynchronizationMode(Item item) {
return getMetadataValue(item, "dspace.orcid.sync-mode")
Expand Down