From 385823f2930b0e32ebc8782aebad61844dc567bf Mon Sep 17 00:00:00 2001 From: Jeff Burke Date: Mon, 30 Mar 2026 14:27:24 -0700 Subject: [PATCH 1/5] CADC-14486 update citation to use status/public endpoint for anon status requests --- .../src/main/webapp/js/citation_landing.js | 2 +- doi/src/main/webapp/openapi.yaml | 2 ++ .../main/webapp/paths/doi-status-public.yaml | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 doi/src/main/webapp/paths/doi-status-public.yaml diff --git a/citation/src/main/webapp/js/citation_landing.js b/citation/src/main/webapp/js/citation_landing.js index 5bdb0c00..b2e0f5dc 100644 --- a/citation/src/main/webapp/js/citation_landing.js +++ b/citation/src/main/webapp/js/citation_landing.js @@ -94,7 +94,7 @@ page.setProgressBar('busy') return new Promise(function (resolve, reject) { - var statusUrl = serviceURL + '/' + doiName + '/status' + var statusUrl = serviceURL + '/' + doiName + '/status/public' var request = new XMLHttpRequest() // 'load' is the XMLHttpRequest 'finished' event diff --git a/doi/src/main/webapp/openapi.yaml b/doi/src/main/webapp/openapi.yaml index 4a40ae99..b7773ad5 100644 --- a/doi/src/main/webapp/openapi.yaml +++ b/doi/src/main/webapp/openapi.yaml @@ -24,5 +24,7 @@ paths: $ref: ./paths/doi-mint.yaml /instances/{DOINum}/status: $ref: ./paths/doi-status.yaml + /instances/{DOINum}/status/public: + $ref: ./paths/doi-status-public.yaml /search: $ref: ./paths/doi-search.yaml diff --git a/doi/src/main/webapp/paths/doi-status-public.yaml b/doi/src/main/webapp/paths/doi-status-public.yaml new file mode 100644 index 00000000..d607ee3b --- /dev/null +++ b/doi/src/main/webapp/paths/doi-status-public.yaml @@ -0,0 +1,19 @@ +get: + tags: + - "instances" + summary: "Get the status of a DOI instance" + description: "Get the status of the specified DOI. Include access to public DOIs." + operationId: "getDOIStatusPublic" + parameters: + - $ref: "../components/parameters/doi-doinum.yaml#/doiNum" + responses: + "200": + $ref: "../components/responses/doi-responses.yaml#/get-doi-status-success" + "403": + $ref: "../components/responses/doi-std-responses.yaml#/permission-denied" + "404": + $ref: "../components/responses/doi-std-responses.yaml#/not-found" + "500": + $ref: "../components/responses/doi-std-responses.yaml#/unexpected-server-error" + "503": + $ref: "../components/responses/doi-std-responses.yaml#/temporarily-unavailable" From a4ab483508b73ad9f3c0c456e779cc322c86f65d Mon Sep 17 00:00:00 2001 From: Jeff Burke Date: Mon, 30 Mar 2026 14:29:14 -0700 Subject: [PATCH 2/5] CADC-14486 check for status/public path for anon requests --- doi/src/main/java/ca/nrc/cadc/doi/DoiAction.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doi/src/main/java/ca/nrc/cadc/doi/DoiAction.java b/doi/src/main/java/ca/nrc/cadc/doi/DoiAction.java index 06cc44a4..04b14b33 100644 --- a/doi/src/main/java/ca/nrc/cadc/doi/DoiAction.java +++ b/doi/src/main/java/ca/nrc/cadc/doi/DoiAction.java @@ -168,6 +168,9 @@ protected void init() this.accountPrefix = config.getFirstPropertyValue(DoiInitAction.DATACITE_ACCOUNT_PREFIX_KEY); this.publisherGroupURI = DoiInitAction.getPublisherGroupURI(config); this.doiGroupPrefix = config.getFirstPropertyValue(DoiInitAction.DOI_GROUP_PREFIX_KEY); + if (this.doiGroupPrefix == null) { + this.doiGroupPrefix = ""; + } LocalAuthority localAuthority = new LocalAuthority(); Set gmsServices = localAuthority.getResourceIDs(Standards.GMS_SEARCH_10); @@ -235,6 +238,11 @@ private void parsePath() { if (parts.length > 1) { doiAction = parts[1]; } + // For status requests for individual DOIs, there is need to check + // to see if the DOI is public in order to provide access. + if (parts.length > 2 && (parts[2].equals("public"))) { + includePublic = true; + } } } } From bbb73605b06b731d6094109925b25c92125d1b84 Mon Sep 17 00:00:00 2001 From: Jeff Burke Date: Mon, 30 Mar 2026 14:32:52 -0700 Subject: [PATCH 3/5] CADC-14486 fix to prepend a rafts prefix to the sequential identifiers. --- .../java/ca/nrc/cadc/doi/LifecycleTest.java | 4 +- .../java/ca/nrc/cadc/doi/DoiInitAction.java | 3 +- .../main/java/ca/nrc/cadc/doi/PostAction.java | 40 ++++++- .../java/ca/nrc/cadc/doi/IdentifierTest.java | 103 ++++++++++++++++++ 4 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java diff --git a/doi/src/intTest/java/ca/nrc/cadc/doi/LifecycleTest.java b/doi/src/intTest/java/ca/nrc/cadc/doi/LifecycleTest.java index 60e1c624..c8b0d42b 100644 --- a/doi/src/intTest/java/ca/nrc/cadc/doi/LifecycleTest.java +++ b/doi/src/intTest/java/ca/nrc/cadc/doi/LifecycleTest.java @@ -290,10 +290,10 @@ void update(Resource expected, String doiSuffix, URL doiServiceURL) throws Excep compareResource(expected, actual, true); // remove updated properties - log.info("creaters before: " + expected.getCreators()); + log.debug("creaters before: " + expected.getCreators()); expected.getCreators().remove(creator); expected.getTitles().remove(title); - log.info("creaters after: " + expected.getCreators()); + log.debug("creaters after: " + expected.getCreators()); // Update the DOI actual = doUpdateTest(expected, doiURL); diff --git a/doi/src/main/java/ca/nrc/cadc/doi/DoiInitAction.java b/doi/src/main/java/ca/nrc/cadc/doi/DoiInitAction.java index f22fb23c..28be7b14 100644 --- a/doi/src/main/java/ca/nrc/cadc/doi/DoiInitAction.java +++ b/doi/src/main/java/ca/nrc/cadc/doi/DoiInitAction.java @@ -151,7 +151,7 @@ private static MultiValuedProperties getConfig(boolean verify) { // required properties checkStringKey(props, sb, ok, true, METADATA_PREFIX_KEY); - checkStringKey(props, sb, ok, true, DOI_GROUP_PREFIX_KEY); + checkStringKey(props, sb, ok, true, DOI_IDENTIFIER_PREFIX_KEY); checkStringKey(props, sb, ok, true, DATACITE_MDS_USERNAME_KEY); checkStringKey(props, sb, ok, true, DATACITE_MDS_PASSWORD_KEY); @@ -161,6 +161,7 @@ private static MultiValuedProperties getConfig(boolean verify) { checkURLKey(props, sb, ok, verify, DATACITE_MDS_URL_KEY); // optional properties + checkStringKey(props, sb, ok, false, DOI_GROUP_PREFIX_KEY); checkStringKey(props, sb, ok, false, RANDOM_TEST_ID_KEY); // alternative properties diff --git a/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java b/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java index 16253026..1d2f4b93 100644 --- a/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java +++ b/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java @@ -107,6 +107,8 @@ import java.util.Random; import java.util.Set; import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.security.auth.Subject; import org.apache.log4j.Logger; @@ -286,9 +288,9 @@ private String getNextDOISuffix(VOSURI baseDoiURI) throws Exception { int maxDoi = 0; if (!baseNode.getNodes().isEmpty()) { for (Node childNode : baseNode.getNodes()) { - String[] nameParts = childNode.getName().split("\\."); - if (nameParts[0].equals(currentYear)) { - int curDoiNum = Integer.parseInt(nameParts[1]); + String suffix = extractSuffix(childNode.getName(), currentYear); + if (suffix != null) { + int curDoiNum = Integer.parseInt(suffix); if (curDoiNum > maxDoi) { maxDoi = curDoiNum; } @@ -301,6 +303,38 @@ private String getNextDOISuffix(VOSURI baseDoiURI) throws Exception { return currentYear + "." + formattedDOI; } + /** + * Returns the portion of the input string after the specified argument and a dot. + * + * Examples (arg=26): + * - "26.0001" -> "0001" + * - "RAFTS-26.0001" -> "0001" + * - "25.0001" -> null + * - "RAFTS-27.0001" -> null + * + * @param identifier The string to parse. + * @param year The year to match. + * @return The captured suffix, or null if no match is found. + */ + public static String extractSuffix(String identifier, String year) { + if (identifier == null) { + return null; + } + + // (?:^|.*-) matches either the start of the string or any prefix ending with a dash. + // \\. matches the literal dot. + // (.*) captures everything after the dot. + String regex = "(?:^|.*-)" + year + "\\.(.*)"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(identifier); + + if (matcher.matches()) { + return matcher.group(1); + } + + return null; + } + // methods to assign to private field in Identity public static void assignIdentifier(Object ce, String identifier) { try { diff --git a/doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java b/doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java new file mode 100644 index 00000000..771a9cc4 --- /dev/null +++ b/doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java @@ -0,0 +1,103 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2024. (c) 2024. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * : 5 $ + * + ************************************************************************ + */ + +package ca.nrc.cadc.doi; + +import org.junit.Assert; +import org.junit.Test; + +public class IdentifierTest { + + @Test + public void test() { + + String year = "26"; + + String actual = PostAction.extractSuffix("26.0001", year); + Assert.assertNotNull(actual); + Assert.assertEquals("0001", actual); + + actual = PostAction.extractSuffix("RAFTS-26.0001", year); + Assert.assertNotNull(actual); + Assert.assertEquals("0001", actual); + + actual = PostAction.extractSuffix("25.0001", year); + Assert.assertNull(actual); + + actual = PostAction.extractSuffix("27.0001", year); + Assert.assertNull(actual); + + actual = PostAction.extractSuffix("RAFTS-25.0001", year); + Assert.assertNull(actual); + + actual = PostAction.extractSuffix("RAFTS-27.0001", year); + Assert.assertNull(actual); + } + +} From 690ca1f25955827a6ccc2a9881b249ce63301b4b Mon Sep 17 00:00:00 2001 From: Jeff Burke Date: Mon, 30 Mar 2026 14:54:36 -0700 Subject: [PATCH 4/5] CADC-14486 javadoc fix --- doi/src/main/java/ca/nrc/cadc/doi/PostAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java b/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java index 1d2f4b93..20ffc7d7 100644 --- a/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java +++ b/doi/src/main/java/ca/nrc/cadc/doi/PostAction.java @@ -307,10 +307,10 @@ private String getNextDOISuffix(VOSURI baseDoiURI) throws Exception { * Returns the portion of the input string after the specified argument and a dot. * * Examples (arg=26): - * - "26.0001" -> "0001" - * - "RAFTS-26.0001" -> "0001" - * - "25.0001" -> null - * - "RAFTS-27.0001" -> null + * - "26.0001" = "0001" + * - "RAFTS-26.0001" = "0001" + * - "25.0001" = null + * - "RAFTS-27.0001" = null * * @param identifier The string to parse. * @param year The year to match. From 82bf45a3c15cee56d6ca51fa9128d61b20170dc5 Mon Sep 17 00:00:00 2001 From: Jeff Burke Date: Mon, 30 Mar 2026 15:02:10 -0700 Subject: [PATCH 5/5] CADC-14486 update header date --- doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java b/doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java index 771a9cc4..67e13c17 100644 --- a/doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java +++ b/doi/src/test/java/ca/nrc/cadc/doi/IdentifierTest.java @@ -3,7 +3,7 @@ ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** * - * (c) 2024. (c) 2024. + * (c) 2026. (c) 2026. * Government of Canada Gouvernement du Canada * National Research Council Conseil national de recherches * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6