diff --git a/doc/release-notes/12476-files-as-other.md b/doc/release-notes/12476-files-as-other.md new file mode 100644 index 00000000000..a34a7f4e86a --- /dev/null +++ b/doc/release-notes/12476-files-as-other.md @@ -0,0 +1,11 @@ +When files are given Persistent Identifiers (PIDs) such as a DOI, the DataCite export resourceTypeGeneral is now "Other" instead of "Dataset". Dataverse uses "Dataset" to mean a container for files. For files, "Other" is not ideal, but it's a step as we work with DataCite in https://github.com/datacite/datacite-suggestions/discussions/214 to define an appropriate value for dataset files. See [the guides](https://guides.dataverse.org/en/6.13/installation/config.html#filepidsenabled), #5086, #12476, and #12713. + +## Upgrade Instructions + +1. Optionally, update metadata for files with DataCite DOIs + + If you are using DataCite as a Persistent ID provider and have files that have DOIs, you may want to update their metadata records to pick up the change from "Dataset" to "Other" for resourceTypeGeneral (see #12713). + + We recommend experimenting with a single dataset first (see [docs](https://guides.dataverse.org/en/6.13/admin/dataverses-datasets.html#update-metadata-for-a-published-dataset-at-the-pid-provider)). Depending on how many DOIs need to be changed, you might want to iterate though datasets one by one but an API endpoint is available to process all datasets at once (see [docs](https://guides.dataverse.org/en/6.13/admin/dataverses-datasets.html#update-metadata-for-all-published-datasets-at-the-pid-provider)). + + \ No newline at end of file diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index 360a96e8eb5..a9936794b7d 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -4573,6 +4573,8 @@ If you don't want to register file-based PIDs for your entire installation:: ``curl -X PUT -d 'false' http://localhost:8080/api/admin/settings/:FilePIDsEnabled`` +If you are using DataCite as your PID provider, resourceTypeGeneral will be "Other". See discussion at https://github.com/IQSS/dataverse/issues/5086. + .. _:AllowEnablingFilePIDsPerCollection: :AllowEnablingFilePIDsPerCollection diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java index 954ddc46f36..f323bececfb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/XmlMetadataTemplate.java @@ -885,6 +885,14 @@ private void writeResourceType(XMLStreamWriter xmlw, DvObject dvObject) throws X case DatasetType.DATASET_TYPE_REVIEW -> "Other"; default -> "Dataset"; }; + } else if (dvObject instanceof DataFile) { + // For now, we are giving data files a resourceTypeGeneral of "Other" + // but longer term, we are working with DataCite on a more appropriate + // value. See the following: + // - https://github.com/IQSS/dataverse/issues/12476 + // - https://github.com/IQSS/dataverse/issues/5086 + // - https://github.com/datacite/datacite-suggestions/discussions/214 + resourceType = "Other"; } attributes.put("resourceTypeGeneral", resourceType); if (dvObject instanceof Dataset d) { diff --git a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteRESTfullClient.java b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteRESTfullClient.java index c0b7661022c..0f8de9d612f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteRESTfullClient.java +++ b/src/main/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/DataCiteRESTfullClient.java @@ -298,6 +298,7 @@ public String postMetadata(String metadata) throws IOException { HttpPost httpPost = new HttpPost(this.url + "/metadata"); httpPost.setHeader("Content-Type", "application/xml;charset=UTF-8"); httpPost.setEntity(new StringEntity(metadata, "utf-8")); + logger.log(Level.FINE, "XML to send to DataCite:\n{0}", metadata); HttpResponse response = executeWithRetry(httpPost, "postMetadata"); String data = EntityUtils.toString(response.getEntity(), encoding); if (response.getStatusLine().getStatusCode() != 201) { diff --git a/src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/XmlMetadataTemplateTest.java b/src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/XmlMetadataTemplateTest.java index 19da198399a..0f2c8fbdd18 100644 --- a/src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/XmlMetadataTemplateTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/pidproviders/doi/datacite/XmlMetadataTemplateTest.java @@ -2,6 +2,8 @@ import edu.harvard.iq.dataverse.ControlledVocabularyValue; import edu.harvard.iq.dataverse.DataCitation; +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.FileMetadata; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetAuthor; import edu.harvard.iq.dataverse.DatasetField; @@ -53,6 +55,9 @@ import javax.xml.transform.stream.StreamSource; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.extension.ExtendWith; @@ -90,6 +95,56 @@ public static void setupMocks() { } + @ParameterizedTest + @EnumSource(value = VersionState.class, names = {"DRAFT", "RELEASED", "DEACCESSIONED"}) + public void testFileResourceTypeGeneral(VersionState state) { + Dataset dataset = resourceTypeTestDataset(DatasetType.DATASET_TYPE_DATASET); + DatasetVersion version = dataset.getLatestVersionForCopy(); + version.setVersionState(state); + version.setVersionNumber(1L); + version.setMinorVersionNumber(0L); + version.setReleaseTime(java.sql.Timestamp.valueOf("2026-01-01 00:00:00")); + DataFile file = new DataFile(); + file.setOwner(dataset); + file.setGlobalId(new GlobalId("doi", "10.5072", "FK2/ABCDEF/FILE", null, null, null)); + file.setFilesize(10L); + FileMetadata metadata = new FileMetadata(); + metadata.setDataFile(file); + metadata.setDatasetVersion(version); + file.setFileMetadatas(List.of(metadata)); + + String xml = new XmlMetadataTemplate(new DoiMetadata()).generateXML(file); + + assertEquals("Other", XmlPath.from(xml).getString("resource.resourceType.@resourceTypeGeneral")); + assertEquals("", XmlPath.from(xml).getString("resource.resourceType")); + } + + @ParameterizedTest + @CsvSource({"dataset, Dataset", "software, Software", "workflow, Workflow", "review, Other", "custom, Dataset"}) + public void testDatasetResourceTypeGeneral(String datasetType, String expectedResourceType) { + Dataset dataset = resourceTypeTestDataset(datasetType); + + String xml = new XmlMetadataTemplate(new DoiMetadata()).generateXML(dataset); + + assertEquals(expectedResourceType, XmlPath.from(xml).getString("resource.resourceType.@resourceTypeGeneral")); + assertEquals("review".equals(datasetType) ? "Review" : "", XmlPath.from(xml).getString("resource.resourceType")); + } + + private Dataset resourceTypeTestDataset(String typeName) { + Dataset dataset = new Dataset(); + dataset.setGlobalId(new GlobalId("doi", "10.5072", "FK2/ABCDEF", null, null, null)); + DatasetType type = new DatasetType(); + type.setName(typeName); + dataset.setDatasetType(type); + DatasetVersion version = new DatasetVersion(); + version.setDataset(dataset); + version.setVersionState(VersionState.DRAFT); + version.setDatasetFields(new ArrayList<>()); + version.setTermsOfUseAndAccess(new TermsOfUseAndAccess()); + dataset.setVersions(new ArrayList<>(List.of(version))); + return dataset; + } + /** * A minimal example to assure that the XMLMetadataTemplate generates output * consistent with the DataCite XML v4.5 schema.