Skip to content

Commit

Permalink
Merged in DSC-1497 (pull request DSpace#1595)
Browse files Browse the repository at this point in the history
[DSC-1497] Add Authority SOURCE ref on the lookup results

Approved-by: Stefano Maffei
  • Loading branch information
eskander17 authored and steph-ieffam committed Feb 12, 2024
2 parents bc34a4c + 55da2ca commit 94f0433
Show file tree
Hide file tree
Showing 16 changed files with 270 additions and 11 deletions.
19 changes: 19 additions & 0 deletions dspace-api/src/main/java/org/dspace/content/authority/Choice.java
Expand Up @@ -48,6 +48,8 @@ public class Choice {

public Map<String, String> extras = new HashMap<String, String>();

public String source = "local";

public Choice() {
}

Expand Down Expand Up @@ -80,6 +82,23 @@ public Choice(String authority, String label, String value, Map<String, String>
this.extras = extras;
}

/**
* Constructor to quickly setup the data object for basic authorities. The choice is assumed to be selectable.
*
* @param authority the authority key
* @param value the text value to store in the metadata
* @param label the value to display to the user
* @param extras a key value map of extra information related to this choice
* @param source authority SOURCE reference
*/
public Choice(String authority, String label, String value, Map<String, String> extras, String source) {
this.authority = authority;
this.label = label;
this.value = value;
this.extras = extras;
this.source = source;
}

/**
* Constructor for common need of Hierarchical authorities that want to
* explicitely set the selectable flag
Expand Down
Expand Up @@ -79,6 +79,8 @@ public class ItemAuthority implements ChoiceAuthority, LinkableEntityAuthority {
// map of field key to presentation type
protected Map<String, String> externalSource = new HashMap<String, String>();

public static final String DEFAULT = "local";

// punt! this is a poor implementation..
@Override
public Choices getBestMatch(String text, String locale) {
Expand Down Expand Up @@ -174,7 +176,7 @@ private List<Choice> getChoiceListFromQueryResults(SolrDocumentList results, Str
Map<String, String> extras = ItemAuthorityUtils.buildExtra(getPluginInstanceName(), doc);
return new Choice((String) doc.getFieldValue("search.resourceid"),
title,
title, extras);
title, extras, DEFAULT);
}).collect(Collectors.toList());
}

Expand Down Expand Up @@ -297,4 +299,9 @@ private Context getContext() {
return context != null ? context : new Context();
}

protected String getSource() {
return configurationService.getProperty(
"cris.ItemAuthority." + authorityName + ".source", DEFAULT);
}

}
Expand Up @@ -98,7 +98,7 @@ private Choice convertToChoice(ImportRecord record) {
String code = getMetadataValue(record, "oairecerif", "funding", "identifier");
String authority = getAuthorityPrefix() + code;
String label = StringUtils.isNotBlank(code) ? value + "(" + code + ")" : value;
return new Choice(authority, value, label, getOpenAireExtra(code));
return new Choice(authority, value, label, getOpenAireExtra(code), getSource());
}

private String getMetadataValue(ImportRecord record, String schema, String element, String qualifier) {
Expand Down
Expand Up @@ -113,7 +113,7 @@ private Choice convertToChoice(ExpandedResult result) {
String title = getTitle(result);
String authority = composeAuthorityValue(result.getOrcidId());
Map<String, String> extras = composeExtras(result);
return new Choice(authority, title, title, extras);
return new Choice(authority, title, title, extras, getSource());
}

private String getTitle(ExpandedResult result) {
Expand Down
Expand Up @@ -64,7 +64,7 @@ private List<Choice> getChoiceFromRORQueryResults(Collection<ImportRecord> orgUn
return orgUnits
.stream()
.map(orgUnit -> new Choice(composeAuthorityValue(getIdentifier(orgUnit)), getName(orgUnit),
getName(orgUnit), buildExtras(orgUnit)))
getName(orgUnit), buildExtras(orgUnit), getSource()))
.collect(Collectors.toList());
}

Expand Down
Expand Up @@ -128,7 +128,7 @@ private Choice convertToChoice(SHERPAJournal journal) {
String authority = composeAuthorityValue(journal);
Map<String, String> extras = getSherpaExtra(journal);
String title = journal.getTitles().get(0);
return new Choice(authority, title, title, extras);
return new Choice(authority, title, title, extras, getSource());
}

private Map<String, String> getSherpaExtra(SHERPAJournal journal) {
Expand Down
Expand Up @@ -50,7 +50,9 @@ protected Choice[] addExternalResults(String text, Choices choices, int start, i
for (AuthorityValue val : values) {
if (added < max) {
Map<String, String> extras = getZDBExtra(val);
results.add(new Choice(val.generateString(), val.getValue(), val.getValue(), extras));
results.add(
new Choice(val.generateString(), val.getValue(), val.getValue(), extras, getSource())
);
added++;
}
}
Expand Down
Expand Up @@ -35,6 +35,7 @@ public VocabularyEntryDetailsRest convert(Choice choice, Projection projection)
entry.setDisplay(choice.label);
entry.setId(mapToId(choice));
entry.setOtherInformation(choice.extras);
entry.setSource(choice.source);
entry.setSelectable(choice.selectable);
return entry;
}
Expand Down
Expand Up @@ -29,6 +29,7 @@ public class VocabularyEntryDetailsRest extends BaseObjectRest<String> {
private String display;
private String value;
private Map<String, String> otherInformation;
private String source;
private boolean selectable;
@JsonIgnore
private boolean inHierarchicalVocabulary = false;
Expand Down Expand Up @@ -102,4 +103,13 @@ public void setInHierarchicalVocabulary(boolean isInHierarchicalVocabulary) {
public boolean isInHierarchicalVocabulary() {
return inHierarchicalVocabulary;
}

public String getSource() {
return source;
}

public void setSource(String source) {
this.source = source;
}

}
Expand Up @@ -26,6 +26,7 @@ public class VocabularyEntryRest implements RestModel {
private String display;
private String value;
private Map<String, String> otherInformation;
private String source;

/**
* The Vocabulary Entry Details resource if available related to this entry
Expand Down Expand Up @@ -73,6 +74,14 @@ public VocabularyEntryDetailsRest getVocabularyEntryDetailsRest() {
return vocabularyEntryDetailsRest;
}

public String getSource() {
return source;
}

public void setSource(String source) {
this.source = source;
}

@Override
public String getType() {
return VocabularyEntryRest.NAME;
Expand Down
Expand Up @@ -129,6 +129,7 @@ public VocabularyEntryRest convertEntry(Choice choice, String authorityName, boo
if (StringUtils.isNotBlank(choice.authority)) {
entry.setVocabularyEntryDetailsRest(converter.toRest(choice, projection));
}
entry.setSource(choice.source);
return entry;
}

Expand Down
Expand Up @@ -29,6 +29,7 @@
import org.dspace.builder.ItemBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.authority.ItemAuthority;
import org.dspace.content.authority.service.ChoiceAuthorityService;
import org.dspace.core.service.PluginService;
import org.dspace.eperson.EPerson;
Expand Down Expand Up @@ -264,7 +265,8 @@ public void singleItemAuthorityWithoutOrgUnitTest() throws Exception {
"Author 1", "Author 1", "vocabularyEntry",
Map.of("data-oairecerif_author_affiliation", "", "oairecerif_author_affiliation", "",
"data-person_identifier_orcid", "",
"person_identifier_orcid", ""))
"person_identifier_orcid", ""),
ItemAuthority.DEFAULT)
)))
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
}
Expand Down Expand Up @@ -888,6 +890,58 @@ public void authorCoarseAuthorityTests() throws Exception {
person4Id, "Cortese, Claudio", "Cortese, Claudio", "vocabularyEntry"))));
}

@Test
public void itemAuthoritySourceReferenceTest() throws Exception {
context.turnOffAuthorisationSystem();

configurationService.setProperty("plugin.named.org.dspace.content.authority.ChoiceAuthority",
new String[] { "org.dspace.content.authority.ItemAuthority = PersonAuthority" });

configurationService.setProperty("choices.presentation.dc.contributor.author", "suggest");
configurationService.setProperty("authority.controlled.dc.contributor.author", "true");

configurationService.setProperty("cris.ItemAuthority.PersonAuthority.entityType", "EntityPerson");

// set authority source reference
configurationService.setProperty("cris.ItemAuthority.PersonAuthority.source", "ORCID");

// These clears have to happen so that the config is actually reloaded in those
// classes. This is needed for
// the properties that we're altering above and this is only used within the
// tests
pluginService.clearNamedPluginClasses();
choiceAuthorityService.clearCache();

parentCommunity = CommunityBuilder.createCommunity(context).build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).build();

Item person1 = ItemBuilder.createItem(context, col1)
.withTitle("Person 1")
.withType("mytype")
.withEntityType("EntityPerson").build();

ItemBuilder.createItem(context, col1)
.withTitle("Person 2")
.withEntityType("EntityPerson")
.build();

ItemBuilder.createItem(context, col1)
.withTitle("Person 3")
.withType("anotherType")
.withEntityType("EntityPerson").build();

context.restoreAuthSystemState();

String token = getAuthToken(eperson.getEmail(), password);
getClient(token)
.perform(get("/api/submission/vocabularies/PersonAuthority/entries").param("filter", "Person"))
.andExpect(status().isOk()).andExpect(jsonPath("$.page.totalElements", Matchers.is(1)))
.andExpect(jsonPath("$._embedded.entries",
Matchers.containsInAnyOrder(ItemAuthorityMatcher.matchItemAuthorityWithOtherInformations(
person1.getID().toString(), "Person 1", "Person 1", "vocabularyEntry", Map.of(),
ItemAuthority.DEFAULT))));
}

@Override
@After
// We need to cleanup the authorities cache once than the configuration has been restored
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.dspace.builder.ItemBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.authority.ItemAuthority;
import org.dspace.content.authority.OrcidAuthority;
import org.dspace.orcid.client.OrcidClient;
import org.dspace.orcid.client.OrcidConfiguration;
Expand Down Expand Up @@ -712,6 +713,101 @@ public void testWithAffiliationExtra() throws Exception {
verifyNoMoreInteractions(orcidClientMock);
}

@Test
public void testSourceReference() throws Exception {

List<ExpandedResult> orcidSearchResults = List.of(
expandedResult("Author", "From Orcid 1", "0000-1111-2222-3333"),
expandedResult("AUTHOR", "FROM ORCID 2", "0000-2222-3333-4444"));

String expectedQuery = "(given-names:author+OR+family-name:author+OR+other-names:author)";

when(orcidClientMock.expandedSearch(READ_PUBLIC_TOKEN, expectedQuery, 0, 20))
.thenReturn(expandedSearch(2, orcidSearchResults));

String token = getAuthToken(eperson.getEmail(), password);
getClient(token).perform(get("/api/submission/vocabularies/AuthorAuthority/entries")
.param("filter", "author"))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.entries", containsInAnyOrder(
orcidEntry("From Orcid 1 Author", REFERENCE, "0000-1111-2222-3333", getSource()),
orcidEntry("From Orcid 2 Author", REFERENCE, "0000-2222-3333-4444", getSource()))))
.andExpect(jsonPath("$.page.size", Matchers.is(20)))
.andExpect(jsonPath("$.page.totalPages", Matchers.is(1)))
.andExpect(jsonPath("$.page.totalElements", Matchers.is(2)));

verify(orcidClientMock).getReadPublicAccessToken();
verify(orcidClientMock).expandedSearch(READ_PUBLIC_TOKEN, expectedQuery, 0, 20);
verifyNoMoreInteractions(orcidClientMock);
}

@Test
public void testMultipleSourcesReferences() throws Exception {
context.turnOffAuthorisationSystem();

List<ExpandedResult> orcidSearchResults = List.of(
expandedResult("Author", "From Orcid 1", "0000-1111-2222-3333"),
expandedResult("AUTHOR", "FROM ORCID 2", "0000-2222-3333-4444"));

String expectedQuery = "(given-names:author+OR+family-name:author+OR+other-names:author)";

when(orcidClientMock.expandedSearch(READ_PUBLIC_TOKEN, expectedQuery, 0, 18))
.thenReturn(expandedSearch(2, orcidSearchResults));

parentCommunity = CommunityBuilder.createCommunity(context).build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).build();

Item orgUnit_1 = ItemBuilder.createItem(context, col1)
.withTitle("OrgUnit_1")
.withEntityType("orgunit")
.build();

Item orgUnit_2 = ItemBuilder.createItem(context, col1)
.withTitle("OrgUnit_2")
.withEntityType("orgunit")
.build();

Item author_1 = ItemBuilder.createItem(context, col1)
.withTitle("Author 1")
.withPersonMainAffiliation(orgUnit_1.getName(), orgUnit_1.getID().toString())
.withEntityType("person")
.build();

Item author_2 = ItemBuilder.createItem(context, col1)
.withTitle("Author 2")
.withPersonMainAffiliation(orgUnit_2.getName(), orgUnit_2.getID().toString())
.withEntityType("person")
.build();

context.restoreAuthSystemState();

String token = getAuthToken(eperson.getEmail(), password);
getClient(token).perform(get("/api/submission/vocabularies/AuthorAuthority/entries")
.param("filter", "author"))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.entries", Matchers.containsInAnyOrder(
// source should be local
ItemAuthorityMatcher.matchItemAuthorityWithOtherInformations(author_1.getID().toString(),
"Author 1", "Author 1", "vocabularyEntry",
Map.of("data-oairecerif_author_affiliation", "OrgUnit_1::" + orgUnit_1.getID(),
"oairecerif_author_affiliation", "OrgUnit_1::" + orgUnit_1.getID(),
"data-person_identifier_orcid", "",
"person_identifier_orcid", ""),
ItemAuthority.DEFAULT),
ItemAuthorityMatcher.matchItemAuthorityWithOtherInformations(author_2.getID().toString(),
"Author 2", "Author 2", "vocabularyEntry",
Map.of("data-oairecerif_author_affiliation", "OrgUnit_2::" + orgUnit_2.getID(),
"oairecerif_author_affiliation", "OrgUnit_2::" + orgUnit_2.getID(),
"data-person_identifier_orcid", "",
"person_identifier_orcid", ""),
ItemAuthority.DEFAULT),
// source should be orcid as configured
orcidEntry("From Orcid 1 Author", REFERENCE, "0000-1111-2222-3333", getSource()),
orcidEntry("From Orcid 2 Author", REFERENCE, "0000-2222-3333-4444", getSource())
)))
.andExpect(jsonPath("$.page.totalElements", Matchers.is(4)));
}

private ExpandedSearch buildExpandedSearchFromSublist(List<ExpandedResult> totalResults, int start, int rows) {
int total = totalResults.size();
if (start > total) {
Expand Down Expand Up @@ -783,6 +879,12 @@ private Matcher<? super Object> orcidEntry(String title, String authorityPrefix,
title, "vocabularyEntry", ORCID_INFO, orcid);
}

private Matcher<? super Object> orcidEntry(String title, String authorityPrefix, String orcid, String source) {
String authority = authorityPrefix + "ORCID::" + orcid;
return ItemAuthorityMatcher.matchItemAuthorityWithOtherInformations(authority, title,
title, "vocabularyEntry", ORCID_INFO, orcid, source);
}

private Matcher<? super Object> orcidEntryWithAffiliation(String title, String authorityPrefix,
String orcid, String affiliation) {
String authority = authorityPrefix + "ORCID::" + orcid;
Expand All @@ -800,4 +902,9 @@ private Matcher<? super Object> orcidEntryWithAffiliation(String title, String a
private String id(Item item) {
return item.getID().toString();
}

private String getSource() {
return configurationService.getProperty(
"cris.ItemAuthority.AuthorAuthority.source", ItemAuthority.DEFAULT);
}
}

0 comments on commit 94f0433

Please sign in to comment.