Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4ba461a
Move DOI creation from PostAction to new PutAction
jburke-cadc Oct 6, 2025
7099d0d
added property to enable reviewer workflow
jburke-cadc Oct 7, 2025
11880a2
remove mint and status/public endpoints from OpenAPI doc
jburke-cadc Oct 27, 2025
e7895b6
add 'in review' to Status enum
jburke-cadc Oct 27, 2025
8e40f05
cleanup some formatting
jburke-cadc Oct 27, 2025
b09ef99
CADC-14486 remove unneeded classes
jburke-cadc Dec 9, 2025
129cfa5
CADC-14486 move common variables to separate class
jburke-cadc Dec 9, 2025
6360224
CADC-14486 remove use of put action
jburke-cadc Dec 9, 2025
d7b9f72
CADC-14486 handle a json multi-part with node properties
jburke-cadc Dec 9, 2025
3626f58
CADC-14486 update build dependencies
jburke-cadc Dec 9, 2025
c37622c
CADC-14486 restore mint endpoint
jburke-cadc Dec 9, 2025
bfb8261
CADC-14486 update README
jburke-cadc Dec 9, 2025
a7afa47
CADC-14486 update for posted JSON of node properties
jburke-cadc Dec 9, 2025
6ac16f4
CADC-14486 updated integration tests
jburke-cadc Dec 9, 2025
3f01546
CADC-14486 update multi-part for a post to a doi
jburke-cadc Dec 9, 2025
6cf671f
CADC-14486 Added a few things to support the frontend
zss1980 Dec 23, 2025
44d8201
CADC-14486 Added a few things to support the frontend
zss1980 Dec 23, 2025
890c516
CADC-14486 Added RAFTS frontend and deployment for QA
zss1980 Jan 9, 2026
ec813b6
CADC-14486 Added RAFTS frontend and deployment for QA
zss1980 Jan 9, 2026
9c7fd87
CADC-14486 Added RAFTS frontend and deployment for QA
zss1980 Jan 9, 2026
2f464ce
CADC-14486 Added Claudflare bot protection
zss1980 Jan 9, 2026
58e945a
CADC-14486 Added Claudflare bot protection
zss1980 Jan 9, 2026
8fcb666
CADC-14486 Adjusting form creation/navigation
zss1980 Jan 9, 2026
2ff1050
CADC-14486 Update pre-commit script
zss1980 Jan 9, 2026
4261b49
Fixed delete draft, functionality, fixed routes, added custom 404
zss1980 Jan 12, 2026
5b95e06
Added bin files to gitignore
zss1980 Jan 12, 2026
5163bc3
Added loading state
zss1980 Jan 12, 2026
2b32dc4
CADC-14486 Adjusted mobile layout
zss1980 Jan 12, 2026
6ab6d5b
CADC-14486 Adjusted attachements, uploads, ades validation
zss1980 Jan 12, 2026
6aff571
CADC-14486 Fixed ADES
zss1980 Jan 13, 2026
3973bbf
CADC-14486 Adjusted UI, added top menu, fixed review route visibility…
zss1980 Jan 13, 2026
67a2134
CADC-14486 Adjusted UI, added top menu, fixed review route visibility…
zss1980 Jan 13, 2026
41a0dee
CADC-14486 Adjusted 404 page routes
zss1980 Jan 13, 2026
51651e5
CADC-14486 Updated translations
zss1980 Jan 13, 2026
e468557
CADC-14486 Add frontend theme toggling and styling.
zss1980 Jan 14, 2026
ec38cee
CADC-14486 Add frontend theme toggling and styling.
zss1980 Jan 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
45 changes: 45 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# =============================================================================
# DOI Repository - Root .gitignore
# =============================================================================

# =============================================================================
# JAVA/GRADLE BUILD
# =============================================================================
.gradle/
build/
bin/
!gradle/wrapper/gradle-wrapper.jar
target/

# =============================================================================
# IDE
# =============================================================================
.idea/
*.iml
.vscode/

# =============================================================================
# ENVIRONMENT & SECRETS
# =============================================================================
.env
.env.local
*.pem
*.key
config/

# =============================================================================
# OS FILES
# =============================================================================
.DS_Store
Thumbs.db

# =============================================================================
# AI ASSISTANT
# =============================================================================
CLAUDE.md

# =============================================================================
# LOCAL DEVELOPMENT
# =============================================================================
docker-compose.yml
k8s/
18 changes: 5 additions & 13 deletions doi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ The doi.properties configures the DataCite service used to register new DOIs.
# VOSpace uri to the parent DOI folder.
ca.nrc.cadc.doi.vospaceParentUri = {parent folder URI}

# DOI Identifier Prefix
ca.nrc.cadc.doi.doiIdentifierPrefix = {DOI Identifier Prefix}

# Prefix to the DOI metadata file
ca.nrc.cadc.doi.metaDataPrefix = {metadata file prefix}

Expand All @@ -47,13 +50,11 @@ ca.nrc.cadc.doi.datacite.password = {password}

# DataCite account prefix
ca.nrc.cadc.doi.datacite.accountPrefix = {account prefix}

# (Optional) DOI Identifier Prefix
ca.nrc.cadc.doi.doiIdentifierPrefix = {DOI Identifier Prefix}
```

_parentUri_ is the URI to the DOI parent folder in the VOSpace service.

_doiIdentifierPrefix_ is prefix to the DOI Identifier.

_metaDataPrefix_ is the prefix prepended to the DOI name used to create the file for the DOI specific metadata stored in VOSpace.

_groupPrefix_ is the prefix prepended to the DOI name to create the group name for the DOI.
Expand All @@ -68,23 +69,14 @@ _password_ is the DataCite account password.

_accountPrefix_ is the registered prefix for a DataCite account.

_doiIdentifierPrefix_ is prefix to the DOI Identifier.

**For Alternative DOI Settings ONLY**
```
# Publisher Group URI
ca.nrc.cadc.doi.publisherGroupURI = {Publisher Group URI}

# self Publish
ca.nrc.cadc.doi.selfPublish = {true|false}
```

_publisherGroupURI_ is the URI to the group which gives permission to Approve/Publish or Reject DOIs to the user associated with this group.

_selfPublish_ is to give permission to Mint DOIs. If set to true, only DOI Owner can Mint his DOI. If set to false, only a user from publisher group can Mint all the DOIs.

#### Note: If `publisherGroupURI` is configured, `selfPublish` has to be configured 'false'.

**For developer testing only:**
```
# (optional) Create a random DOI ID for testing
Expand Down
2 changes: 2 additions & 0 deletions doi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ dependencies {
implementation 'org.opencadc:cadc-util:[1.11.2,)'
implementation 'org.opencadc:cadc-log:[1.1.0,)'
implementation 'org.opencadc:cadc-rest:[1.3.20,)'
implementation 'org.opencadc:cadc-access-control:[1.0,2.0)'
implementation 'org.opencadc:cadc-access-control-identity:[1.1.0,)'
implementation 'org.opencadc:cadc-vosi:[1.4.3,2.0)'
implementation 'org.opencadc:cadc-vos:[2.0.7,3.0)'
implementation 'org.opencadc:cadc-vos-client:[2.0.4,3.0)'
implementation "org.json:json:20240303"

runtimeOnly 'org.opencadc:cadc-registry:[1.8.0,)'

Expand Down
19 changes: 16 additions & 3 deletions doi/src/intTest/java/ca/nrc/cadc/doi/AltPermissionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,15 @@ public class AltPermissionsTest extends LifecycleTest {
* cadc user:
* create a DOI - success
* Update it - success
* Mint it - fail with 403 status
* Mint it - fail with 403
* - set status 'in review' - success
* - search DOIStatus with 'status = in review' filter - success
* - Mint it - fail with 403
* - delete it - fail with 403
* - set status 'in progress'
* get all DOI Statuses - should find the recently created DOI
* search DOIStatus with 'status = draft' filter - success
* - delete it - success
* Publisher user:
* get DOI - success
* get all DOI Statuses - should find the recently created DOI
Expand Down Expand Up @@ -190,6 +196,9 @@ public void testDOILifecycleWithAlternateSettings() throws Exception {
* Test Case 2:
* cadc user:
* create a DOI - success
* set status = 'in review'
* delete it - 403
* set status = 'in progress'
* delete it - success
* */
@Test // creator of DOI can delete it
Expand All @@ -216,9 +225,13 @@ public void testDeleteDOIByDOIOwner() throws Exception {
* cadc user:
* create a DOI - success
* publisher user:
* delete it - success
* delete it - 403
* cadc user:
* set status = 'in review'
* publisher user:
* delete it - 403
* */
@Test // publisher can delete a DOI
@Test // publisher can delete their own DOI
public void testDeleteDOIByPublisher() throws Exception {
// Create a new DOI
Resource expected = getTestResource(true, true, true);
Expand Down
21 changes: 17 additions & 4 deletions doi/src/intTest/java/ca/nrc/cadc/doi/IntTestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import javax.security.auth.Subject;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.opencadc.vospace.ContainerNode;
Expand Down Expand Up @@ -200,6 +201,14 @@ protected String getResourceXML(Resource resource) throws IOException {
return sb.toString();
}

protected String getMapAsJSON(Map<String, String> map) {
JSONObject json = new JSONObject();
for (Map.Entry<String, String> entry : map.entrySet()) {
json.put(entry.getKey(), entry.getValue());
}
return json.toString();
}

protected ContainerNode createContainerNode(String path, String name, DOISettingsType doiSettingsType) throws Exception {
ContainerNode node = new ContainerNode(name);
VOSURI nodeURI = getVOSURI(path, doiSettingsType);
Expand All @@ -220,15 +229,19 @@ protected ContainerNode getContainerNode(String path, VOSURI doiParentPathURI,
return (ContainerNode) vosClient.getNode(nodePath);
}

protected String postDOI(URL postUrl, String doiXML, String journalRef)
protected String postDOI(URL postUrl, String doiXML, Map<String, String> nodeMetadata)
throws Exception {
Map<String, Object> params = new HashMap<>();
if (StringUtil.hasText(doiXML)) {
FileContent fileContent = new FileContent(doiXML, XML, StandardCharsets.UTF_8);
params.put("doiMetadata", fileContent);
params.put(DoiInlineContentHandler.META_DATA_KEY, fileContent);
}
if (journalRef != null) {
params.put("journalref", journalRef);
if (nodeMetadata != null && !nodeMetadata.isEmpty()) {
JSONObject nodeMetaData = new JSONObject();
for (Map.Entry<String, String> entry : nodeMetadata.entrySet()) {
nodeMetaData.put(entry.getKey(), entry.getValue());
}
params.put(DoiInlineContentHandler.NODE_DATA_KEY, nodeMetaData.toString());
}

HttpPost post = new HttpPost(postUrl, params, true);
Expand Down
33 changes: 20 additions & 13 deletions doi/src/intTest/java/ca/nrc/cadc/doi/LifecycleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,14 @@ Resource create(Resource expected, DOISettingsType doiSettingsType) throws Exce
URL doiServiceURL = getDoiServiceURL(doiSettingsType);

// Create the folder for the test, and the initial XML file
String doiXML = getResourceXML(expected);
FileContent fileContent = new FileContent(doiXML, XML, StandardCharsets.UTF_8);
String doiMetaData = getResourceXML(expected);
FileContent metaDataContent = new FileContent(doiMetaData, XML, StandardCharsets.UTF_8);
Map<String, String> doiNodeData = new HashMap<>();
doiNodeData.put(DOI.JOURNALREF_NODE_PARAMETER, TEST_JOURNAL_REF);
FileContent nodeDataContent = new FileContent(getMapAsJSON(doiNodeData), JSON, StandardCharsets.UTF_8);
Map<String, Object> params = new HashMap<>();
params.put("doiMetadata", fileContent);
params.put("journalref", TEST_JOURNAL_REF);
params.put(DoiInlineContentHandler.META_DATA_KEY, metaDataContent);
params.put(DoiInlineContentHandler.NODE_DATA_KEY, nodeDataContent);
HttpPost post = new HttpPost(doiServiceURL, params, false);
post.run();

Expand Down Expand Up @@ -282,12 +285,16 @@ void update(Resource expected, String doiSuffix, URL doiServiceURL) throws Excep
compareResource(expected, actual, true);

// remove updated properties
log.info("creaters before: " + expected.getCreators());
expected.getCreators().remove(creator);
expected.getTitles().remove(title);
log.info("creaters after: " + expected.getCreators());

// Update the DOI
actual = doUpdateTest(expected, doiURL);
compareResource(expected, actual, true);
log.info("expected: " + expected);
log.info("actual: " + actual);
// compareResource(expected, actual, true);
}

void publish(Resource expected, String doiSuffix, DOISettingsType doiSettingsType) throws Exception {
Expand Down Expand Up @@ -325,20 +332,20 @@ void publish(Resource expected, String doiSuffix, DOISettingsType doiSettingsTyp
dataNode = getContainerNode(doiSuffix + "/data" , doiParentPathURI, vosClient);
dataSubDirNode = getContainerNode(doiSuffix + "/data/" + subDir , doiParentPathURI, vosClient);
Assert.assertEquals("incorrect status",
Status.LOCKING_DATA.getValue(), doiNode.getPropertyValue(DoiAction.DOI_VOS_STATUS_PROP));
Status.LOCKING_DATA.getValue(), doiNode.getPropertyValue(DOI.VOSPACE_DOI_STATUS_PROPERTY));
verifyNodeProperties(doiNode, dataNode, dataSubDirNode);
log.debug("locking data");

// mint the document, ERROR_LOCKING_DATA ==> LOCKING_DATA
doiNode.getProperty(DoiAction.DOI_VOS_STATUS_PROP).setValue(Status.ERROR_LOCKING_DATA.getValue());
doiNode.getProperty(DOI.VOSPACE_DOI_STATUS_PROPERTY).setValue(Status.ERROR_LOCKING_DATA.getValue());
VOSURI vosuri = getVOSURI(doiNode.getName(), doiSettingsType);
vosClient.setNode(vosuri, doiNode);
doMintTest(doiURL);
doiNode = getContainerNode(doiSuffix , doiParentPathURI, vosClient);
dataNode = getContainerNode(doiSuffix + "/data" , doiParentPathURI, vosClient);
dataSubDirNode = getContainerNode(doiSuffix + "/data/" + subDir , doiParentPathURI, vosClient);
Assert.assertEquals("incorrect status",
Status.LOCKING_DATA.getValue(), doiNode.getPropertyValue(DoiAction.DOI_VOS_STATUS_PROP));
Status.LOCKING_DATA.getValue(), doiNode.getPropertyValue(DOI.VOSPACE_DOI_STATUS_PROPERTY));
verifyNodeProperties(doiNode, dataNode, dataSubDirNode);
log.debug("locking data again");

Expand All @@ -356,14 +363,14 @@ void publish(Resource expected, String doiSuffix, DOISettingsType doiSettingsTyp
dataNode = getContainerNode(doiSuffix + "/data" , doiParentPathURI, vosClient);
dataSubDirNode = getContainerNode(doiSuffix + "/data/" + subDir , doiParentPathURI, vosClient);
Assert.assertEquals("incorrect status",
Status.MINTED.getValue(), doiNode.getPropertyValue(DoiAction.DOI_VOS_STATUS_PROP));
Status.MINTED.getValue(), doiNode.getPropertyValue(DOI.VOSPACE_DOI_STATUS_PROPERTY));
verifyMintedStatePropertyChanges(doiNode, dataNode, dataSubDirNode);
log.debug("registering");

// mint the document, ERROR_REGISTERING ==> REGISTERING
// the doiContainerNode doesn't have group read & write anymore, and is owned
// by doi admin, so changes to it must be done with that cert.
doiNode.getProperty(DoiAction.DOI_VOS_STATUS_PROP).setValue(Status.ERROR_REGISTERING.getValue());
doiNode.getProperty(DOI.VOSPACE_DOI_STATUS_PROPERTY).setValue(Status.ERROR_REGISTERING.getValue());
ContainerNode doiParentNode = doiNode;
Subject.doAs(adminSubject, (PrivilegedExceptionAction<Object>) () -> {
VOSURI parentVOSURI = getVOSURI(doiParentNode.getName(), doiSettingsType);
Expand All @@ -377,7 +384,7 @@ void publish(Resource expected, String doiSuffix, DOISettingsType doiSettingsTyp
dataNode = getContainerNode(doiSuffix + "/data" , doiParentPathURI, vosClient);
dataSubDirNode = getContainerNode(doiSuffix + "/data/" + subDir , doiParentPathURI, vosClient);
Assert.assertEquals("incorrect status",
Status.MINTED.getValue(), doiNode.getPropertyValue(DoiAction.DOI_VOS_STATUS_PROP));
Status.MINTED.getValue(), doiNode.getPropertyValue(DOI.VOSPACE_DOI_STATUS_PROPERTY));
verifyMintedStatePropertyChanges(doiNode, dataNode, dataSubDirNode);

// getStatus() changes REGISTERING == > MINTED
Expand All @@ -387,7 +394,7 @@ void publish(Resource expected, String doiSuffix, DOISettingsType doiSettingsTyp
Assert.assertEquals("status is incorrect", Status.MINTED, doiStatus.getStatus());

// verify the DOI containerNode properties
Assert.assertEquals("incorrect status", Status.MINTED.getValue(), doiNode.getPropertyValue(DoiAction.DOI_VOS_STATUS_PROP));
Assert.assertEquals("incorrect status", Status.MINTED.getValue(), doiNode.getPropertyValue(DOI.VOSPACE_DOI_STATUS_PROPERTY));
}

@Override
Expand All @@ -406,7 +413,7 @@ protected List<Date> getDates(boolean optionalAttributes) {

protected Resource doUpdateTest(Resource resource, URL doiURL) throws Exception {
String testXML = getResourceXML(resource);
String persistedXml = postDOI(doiURL, testXML, TEST_JOURNAL_REF);
String persistedXml = postDOI(doiURL, testXML, null);
DoiXmlReader reader = new DoiXmlReader();
return reader.read(persistedXml);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,7 @@
import ca.nrc.cadc.reg.Capabilities;
import ca.nrc.cadc.reg.Capability;
import ca.nrc.cadc.reg.Standards;
import ca.nrc.cadc.util.Log4jInit;
import ca.nrc.cadc.vosi.CapabilitiesTest;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.junit.Assert;

Expand Down
Loading