-
Notifications
You must be signed in to change notification settings - Fork 500
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
#7978: linking ORCID from the metadata tab. #7979
Changes from all commits
e4a9714
ce8882c
8b9b5ea
4d4167a
3dbd1d3
fb148c8
ec466d8
a8c1445
6e571a1
a0e722a
2af4252
7f1a39a
12e8e8c
1e66657
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
### Displaying author's identifier as link | ||
|
||
In the dataset page's metadata tab the author's identifier is displayed as a clickable link, which points to the profile page in the external service (ORCID, VIAF etc.), given that the identifier scheme provides a resolvable landing page. If the identifier does not match the expected scheme, a link is not shown. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,6 @@ | |
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.ResourceBundle; | ||
import javax.persistence.CascadeType; | ||
import javax.persistence.Entity; | ||
import javax.persistence.GeneratedValue; | ||
|
@@ -25,7 +24,11 @@ | |
import javax.persistence.OneToMany; | ||
import javax.persistence.OrderBy; | ||
import javax.persistence.Table; | ||
import javax.persistence.Transient; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
import org.apache.commons.lang3.tuple.ImmutablePair; | ||
import org.apache.commons.lang3.tuple.Pair; | ||
|
||
/** | ||
* | ||
|
@@ -68,6 +71,19 @@ public static DatasetFieldCompoundValue createNewEmptyDatasetFieldCompoundValue( | |
@OrderBy("datasetFieldType ASC") | ||
private List<DatasetField> childDatasetFields = new ArrayList<>(); | ||
|
||
// configurations for link creation | ||
private static final Map<String, Pair<String, String>> linkComponents = Map.of( | ||
"author", new ImmutablePair<>("authorIdentifierScheme", "authorIdentifier") | ||
); | ||
|
||
// field for handling links. Annotation '@Transient' prevents these fields to be saved in DB | ||
@Transient | ||
private Map<DatasetField, Boolean> linkMap = new LinkedHashMap<>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I know maps are optimized for lookup values, so map.contains() faster than the list.contains(). |
||
@Transient | ||
private String linkScheme = null; | ||
@Transient | ||
private String linkValue = null; | ||
Comment on lines
+82
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also it seems unlikely now - this is a compound field and there might be multiple links in one. One might argue that this could even be a suited for a inner wrapping class, holding the data and merge There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Theoretically yes, but in practice a compound field can not have multiple links. A single author might have one name, one identifier scheme and one identifier. Multiple links would be possible of the scheme and id would have its own compound field, which would be a component of the author field. |
||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
@@ -133,15 +149,29 @@ public DatasetFieldCompoundValue copy(DatasetField parent) { | |
return compoundValue; | ||
} | ||
|
||
public Map<DatasetField,String> getDisplayValueMap() { | ||
public Map<DatasetField, String> getDisplayValueMap() { | ||
// todo - this currently only supports child datasetfields with single values | ||
// need to determine how we would want to handle multiple | ||
Map<DatasetField, String> fieldMap = new LinkedHashMap<>(); | ||
linkMap.clear(); | ||
boolean fixTrailingComma = false; | ||
Pair<String, String> linkComponents = getLinkComponents(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again - what happens when there are multiple links in one compound field? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see above, it is not possible now. |
||
linkScheme = null; | ||
linkValue = null; | ||
for (DatasetField childDatasetField : childDatasetFields) { | ||
fixTrailingComma = false; | ||
// skip the value if it is empty or N/A | ||
if (!StringUtils.isBlank(childDatasetField.getValue()) && !DatasetField.NA_VALUE.equals(childDatasetField.getValue())) { | ||
if (linkComponents != null) { | ||
if (fieldNameEquals(childDatasetField, linkComponents.getKey())) { | ||
linkScheme = childDatasetField.getValue(); | ||
} else if (fieldNameEquals(childDatasetField, linkComponents.getValue())) { | ||
linkValue = childDatasetField.getValue(); | ||
if (StringUtils.isNotBlank(linkScheme) && StringUtils.isNotBlank(linkValue)) | ||
linkMap.put(childDatasetField, true); | ||
} | ||
} | ||
|
||
String format = childDatasetField.getDatasetFieldType().getDisplayFormat(); | ||
if (StringUtils.isBlank(format)) { | ||
format = "#VALUE"; | ||
|
@@ -161,8 +191,8 @@ public Map<DatasetField,String> getDisplayValueMap() { | |
//todo: this should be handled in more generic way for any other text that can then be internationalized | ||
// if we need to use replaceAll for regexp, then make sure to use: java.util.regex.Matcher.quoteReplacement(<target string>) | ||
.replace("#EMAIL", BundleUtil.getStringFromBundle("dataset.email.hiddenMessage")) | ||
.replace("#VALUE", sanitizedValue ); | ||
fieldMap.put(childDatasetField,displayValue); | ||
.replace("#VALUE", sanitizedValue); | ||
fieldMap.put(childDatasetField, displayValue); | ||
} | ||
} | ||
|
||
|
@@ -172,7 +202,29 @@ public Map<DatasetField,String> getDisplayValueMap() { | |
|
||
return fieldMap; | ||
} | ||
|
||
|
||
public String getLink() { | ||
return DatasetAuthor.getIdentifierAsUrl(linkScheme, linkValue); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really like the hardcoded behaviour here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DatasetAuthor had already this method, and at first - not being aware of that - I created my solution which lacks the validation aspect of the ID. Since there is another compound field, which has a similar link structure (related publications), in the next round when it comes to implementing those schemas, we should move this function to a different class (either here, or into a 3rd location). |
||
} | ||
|
||
public boolean isLink(DatasetField datasetField) { | ||
return linkMap.containsKey(datasetField) && linkMap.get(datasetField) == true && getLink() != null; | ||
} | ||
|
||
private boolean fieldNameEquals(DatasetField datasetField, String linkTypeComponent) { | ||
return datasetField.getDatasetFieldType().getName().equals(linkTypeComponent); | ||
} | ||
|
||
public boolean isLinkableField() { | ||
return linkComponents.containsKey(parentDatasetField.getDatasetFieldType().getName()); | ||
} | ||
|
||
public Pair<String, String> getLinkComponents() { | ||
if (!isLinkableField()) | ||
return null; | ||
return linkComponents.get(parentDatasetField.getDatasetFieldType().getName()); | ||
} | ||
|
||
private Map<DatasetField, String> removeLastComma(Map<DatasetField, String> mapIn) { | ||
|
||
Iterator<Map.Entry<DatasetField, String>> itr = mapIn.entrySet().iterator(); | ||
|
@@ -192,6 +244,5 @@ private Map<DatasetField, String> removeLastComma(Map<DatasetField, String> mapI | |
} | ||
|
||
return mapIn; | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package edu.harvard.iq.dataverse; | ||
|
||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
public enum ExternalIdentifier { | ||
ORCID("ORCID", "https://orcid.org/%s", "^\\d{4}-\\d{4}-\\d{4}-(\\d{4}|\\d{3}X)$"), | ||
ISNI("ISNI", "http://www.isni.org/isni/%s", "^\\d*$"), | ||
LCNA("LCNA", "http://id.loc.gov/authorities/names/%s", "^[a-z]+\\d+$"), | ||
VIAF("VIAF", "https://viaf.org/viaf/%s", "^\\d*$"), | ||
// GND regex from https://www.wikidata.org/wiki/Property:P227 | ||
GND("GND", "https://d-nb.info/gnd/%s", "^1[01]?\\d{7}[0-9X]|[47]\\d{6}-\\d|[1-9]\\d{0,7}-[0-9X]|3\\d{7}[0-9X]$"), | ||
// note: DAI is missing from this list, because it doesn't have resolvable URL | ||
ResearcherID("ResearcherID", "https://publons.com/researcher/%s/", "^[A-Z\\d][A-Z\\d-]+[A-Z\\d]$"), | ||
ScopusID("ScopusID", "https://www.scopus.com/authid/detail.uri?authorId=%s", "^\\d*$"); | ||
|
||
private String name; | ||
private String template; | ||
private Pattern pattern; | ||
private Matcher matcher; | ||
|
||
ExternalIdentifier(String name, String template, String regex) { | ||
this.template = template; | ||
this.pattern = Pattern.compile(regex); | ||
this.matcher = pattern.matcher(""); | ||
} | ||
|
||
public ExternalIdentifier of(String name) { | ||
System.err.println(name); | ||
for (ExternalIdentifier identifier : values()) { | ||
System.err.println(" vs " + identifier.name); | ||
if (identifier.name.toLowerCase().equals(name.toLowerCase())) { | ||
return identifier; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
public boolean isValidIdentifier(String userInput) { | ||
return matcher.reset(userInput).matches(); | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public String getTemplate() { | ||
return template; | ||
} | ||
|
||
public Pattern getPattern() { | ||
return pattern; | ||
} | ||
|
||
public String format(String idValue) { | ||
return String.format(template, idValue); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like the idea!