diff --git a/examples/affiliation.md b/examples/affiliation.md index 91624d6..e2943d3 100644 --- a/examples/affiliation.md +++ b/examples/affiliation.md @@ -1,3 +1,5 @@ +Note: This example (.json and .js files) currently rely on the ROR v1 API which won't be supported as of ~12/2025. They could be updated to use v2 of the API as the main authorIdandAffiliationUsingORCIDandROR example and ror.js script have.) + The affiliation example illustrates a lookup in ROR.org for the author affiliation field. As with the authors example, it is a simple lookup and fill-in solution. Do not expect changes in the ROR database to be propagated in the Dataset metadata. Two files comprise this example: diff --git a/examples/authorIDandAffilationUsingORCIDandROR.md b/examples/authorIDandAffilationUsingORCIDandROR.md index 2530212..495c28a 100644 --- a/examples/authorIDandAffilationUsingORCIDandROR.md +++ b/examples/authorIDandAffilationUsingORCIDandROR.md @@ -14,6 +14,17 @@ This example requires several files: (These scripts also use jquery and select2 which are already included in Dataverse). +## Dataverse Compatibility note: + +The ROR configuration/script now use ROR's v2 API and require Dataverse 6.9+ for full functionality. +For installations on earlier versions, the ROR organization name will not be added to the DataCite XML metadata. +Installations on <= Dataverse v6.8 should not upgrade their CVocConf configuration (keeping the retrieval-url pointed to ROR's v1 API or should delete the contents of the "retrieval-filtering" object (e.g. set "retrieval-filtering": {} ). + +## ROR Compatibility note: +As of Dec. 2025, ROR will no longer support it's v1 API. To retain ROR functionality, Dataverse sites should update to use the current ror.js script (which uses ROR's v2 API). +Dataverse instances on v6.9+ should also update to use the current :CVocConf configuration. +Dataverse instances using <=v6.8 also need to update the ror.js script but should not update their configuration (or should delete the contents of the retrieval-filtering object as discussed above). + ### How to install: Minimal: diff --git a/examples/config/authorsOrcidAndRor.json b/examples/config/authorsOrcidAndRor.json index 1c04fe6..58d4c4e 100644 --- a/examples/config/authorsOrcidAndRor.json +++ b/examples/config/authorsOrcidAndRor.json @@ -4,7 +4,7 @@ "term-uri-field": "authorAffiliation", "js-url": ["https://gdcc.github.io/dataverse-external-vocab-support/scripts/ror.js","https://gdcc.github.io/dataverse-external-vocab-support/scripts/cvocutils.js"], "protocol": "ror", - "retrieval-uri": "https://api.ror.org/v1/organizations/{0}", + "retrieval-uri": "https://api.ror.org/v2/organizations/{0}", "allow-free-text": true, "prefix": "https://ror.org/", "managed-fields": {}, @@ -26,7 +26,7 @@ }, "termName": { "pattern": "{0}", - "params": ["/name"] + "params": ["/names/types=ror_display/value"] }, "@type": { "pattern": "https://schema.org/Organization" diff --git a/examples/config/demos/rorAuthAffiliation.json b/examples/config/demos/rorAuthAffiliation.json index 80c6c95..144092e 100644 --- a/examples/config/demos/rorAuthAffiliation.json +++ b/examples/config/demos/rorAuthAffiliation.json @@ -4,7 +4,7 @@ "term-uri-field": "authorAffiliation", "js-url": ["/cvoc/js/ror.js","/cvoc/js/cvocutils.js"], "protocol": "ror", - "retrieval-uri": "https://api.ror.org/organizations/{0}", + "retrieval-uri": "https://api.ror.org/v2/organizations/{0}", "allow-free-text": true, "prefix": "https://ror.org/", "managed-fields": {}, @@ -26,7 +26,7 @@ }, "termName": { "pattern": "{0}", - "params": ["/name"] + "params": ["/names/types=ror_display/value"] }, "@type": { "pattern": "https://schema.org/Organization" diff --git a/examples/config/grantNumberAgencyRor.json b/examples/config/grantNumberAgencyRor.json index 078eaed..1b926cd 100644 --- a/examples/config/grantNumberAgencyRor.json +++ b/examples/config/grantNumberAgencyRor.json @@ -4,7 +4,7 @@ "term-uri-field": "grantNumberAgency", "js-url": ["https://qualitativedatarepository.github.io/dataverse-external-vocab-support/scripts/ror.js","https://qualitativedatarepository.github.io/dataverse-external-vocab-support/scripts/cvocutils.js"], "protocol": "ror", - "retrieval-uri": "https://api.ror.org/organizations/{0}", + "retrieval-uri": "https://api.ror.org/v2/organizations/{0}", "allow-free-text": true, "prefix": "https://ror.org/", "managed-fields": {}, @@ -26,7 +26,7 @@ }, "termName": { "pattern": "{0}", - "params": ["/name"] + "params": ["/names/types=ror_display/value"] }, "@type": { "pattern": "https://schema.org/Organization" diff --git a/scripts/affiliation.js b/scripts/affiliation.js index 641a206..a653b64 100644 --- a/scripts/affiliation.js +++ b/scripts/affiliation.js @@ -106,7 +106,7 @@ function createAffiliationModal() { function affiliationsQuery(str) { // Vocabulary search REST call - fetch("https://api.ror.org/organizations?query=" + str) + fetch("https://api.ror.org/v1/organizations?query=" + str) .then(response => response.json()) .then(data => { let table = document.querySelector('#' + affiliationSearchResultsID + ' tbody'); diff --git a/scripts/ror.js b/scripts/ror.js index 5a8aefd..ca49644 100644 --- a/scripts/ror.js +++ b/scripts/ror.js @@ -1,7 +1,7 @@ console.log("ror.js.."); var rorSelector = "span[data-cvoc-protocol='ror']"; var rorInputSelector = "input[data-cvoc-protocol='ror']"; -var rorRetrievalUrl = "https://api.ror.org/v1/organizations"; +var rorRetrievalUrl = "https://api.ror.org/v2/organizations"; var rorIdStem = "https://ror.org/"; var rorPrefix = "ror"; //Max chars that displays well for a child field @@ -62,12 +62,19 @@ function expandRors() { }, success: function(ror, status) { // If found, construct the HTML for display - var name = ror.name; - var altNames = ror.acronyms; + // Find the display name (type: "ror_display" or "label") + const displayName = ror.names.find(n => + n.types && (n.types.includes("ror_display") || n.types.includes("label")) + )?.value || ror.id; + + // Find all acronyms + const acronyms = ror.names + .filter(n => n.types && n.types.includes("acronym")) + .map(n => n.value); - $(rorElement).html(getRorDisplayHtml(name, rorIdStem + id, altNames, false, true)); + $(rorElement).html(getRorDisplayHtml(displayName, rorIdStem + id, acronyms, false, true)); //Store values in localStorage to avoid repeating calls to CrossRef - storeValue(rorPrefix, id, name + "#" + altNames); + storeValue(rorPrefix, id, displayName + "#" + acronyms.join(',')); }, failure: function(jqXHR, textStatus, errorThrown) { // Generic logging - don't need to do anything if 404 (leave @@ -190,14 +197,34 @@ function updateRorInputs() { // Sort the list // Prioritize active orgs .sort((a, b) => Number(b.status === 'active') - Number(a.status === 'active')) + // Extract display name and acronyms from the names array + .map(org => { + // Find the display name (type: "ror_display" or "label") + const displayName = org.names.find(n => + n.types && (n.types.includes("ror_display") || n.types.includes("label")) + )?.value || org.id; + + // Find all acronyms + const acronyms = org.names + .filter(n => n.types && n.types.includes("acronym")) + .map(n => n.value); + + return { + ...org, + name: displayName, + acronyms: acronyms + }; + }) // Prioritize those with this acronym - .sort((a, b) => Number(b.acronyms.includes(params.term)) - Number(a.acronyms.includes(params.term))) + .sort((a, b) => Number(b.acronyms.some(acr => acr === params.term)) - + Number(a.acronyms.some(acr => acr === params.term))) // Prioritize previously used entries - .sort((a, b) => Number(getValue(rorPrefix, b['id'].replace(rorIdStem, '')).name != null) - Number(getValue(rorPrefix, a['id'].replace(rorIdStem, '')).name != null)) + .sort((a, b) => Number(getValue(rorPrefix, b['id'].replace(rorIdStem, '')).name != null) - + Number(getValue(rorPrefix, a['id'].replace(rorIdStem, '')).name != null)) .map( function(x) { return { - text: x.name + ", " + x.id.replace(rorIdStem, '') + ', ' + x.acronyms, + text: x.name + ", " + x.id.replace(rorIdStem, '') + ', ' + x.acronyms.join(','), id: x.id } }) @@ -236,9 +263,18 @@ function updateRorInputs() { 'Accept': 'application/json' }, success: function(ror, status) { - var name = ror.name; + // Find the display name (type: "ror_display" or "label") + const displayName = ror.names.find(n => + n.types && (n.types.includes("ror_display") || n.types.includes("label")) + )?.value || ror.id; + + // Find all acronyms + const acronyms = ror.names + .filter(n => n.types && n.types.includes("acronym")) + .map(n => n.value); + //Display the name and id number in the selection menu - var text = name + ", " + ror.id.replace(rorIdStem, '') + ', ' + ror.acronyms; + var text = displayName + ", " + ror.id.replace(rorIdStem, '') + ', ' + acronyms.join(','); var newOption = new Option(text, id, true, true); $('#' + selectId).append(newOption).trigger('change'); },