Skip to content

Commit

Permalink
Merge pull request IQSS#10246 from IQSS/10240-file-citation
Browse files Browse the repository at this point in the history
file citation via API
  • Loading branch information
sekmiller authored Feb 16, 2024
2 parents 4d529ce + ab0abaf commit 82585f9
Show file tree
Hide file tree
Showing 9 changed files with 290 additions and 23 deletions.
5 changes: 5 additions & 0 deletions doc/release-notes/10240-file-citation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Get file citation as JSON

It is now possible to retrieve via API the file citation as it appears on the file landing page. It is formatted in HTML and encoded in JSON.

This API is not for downloading various citation formats such as EndNote XML, RIS, or BibTeX. This functionality has been requested in https://github.com/IQSS/dataverse/issues/3140 and https://github.com/IQSS/dataverse/issues/9994
58 changes: 57 additions & 1 deletion doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,12 @@ Datasets

**Note** Creation of new datasets is done with a ``POST`` onto a Dataverse collection. See the Dataverse Collections section above.

**Note** In all commands below, dataset versions can be referred to as:
.. _dataset-version-specifiers:

Dataset Version Specifiers
~~~~~~~~~~~~~~~~~~~~~~~~~~

In all commands below, dataset versions can be referred to as:

* ``:draft`` the draft version, if any
* ``:latest`` either a draft (if exists) or the latest published version.
Expand Down Expand Up @@ -2712,6 +2717,8 @@ The fully expanded example above (without environment variables) looks like this
Files
-----
.. _get-json-rep-of-file:
Get JSON Representation of a File
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -3499,6 +3506,55 @@ The fully expanded example above (without environment variables) looks like this
You can download :download:`dct.xml <../../../../src/test/resources/xml/dct.xml>` from the example above to see what the XML looks like.
Get File Citation as JSON
~~~~~~~~~~~~~~~~~~~~~~~~~
This API is for getting the file citation as it appears on the file landing page. It is formatted in HTML and encoded in JSON.
To specify the version, you can use ``:latest-published`` or ``:draft`` or ``1.0`` or any other style listed under :ref:`dataset-version-specifiers`.
When the dataset version is published, authentication is not required:
.. code-block:: bash
export SERVER_URL=https://demo.dataverse.org
export FILE_ID=42
export DATASET_VERSION=:latest-published
curl "$SERVER_URL/api/files/$FILE_ID/versions/$DATASET_VERSION/citation"
The fully expanded example above (without environment variables) looks like this:
.. code-block:: bash
curl "https://demo.dataverse.org/api/files/42/versions/:latest-published/citation"
When the dataset version is a draft or deaccessioned, authentication is required.
By default, deaccessioned dataset versions are not included in the search when applying the :latest or :latest-published identifiers. Additionally, when filtering by a specific version tag, you will get a "unauthorized" error if the version is deaccessioned and you do not enable the ``includeDeaccessioned`` option described below.
If you want to include deaccessioned dataset versions, you must set ``includeDeaccessioned`` query parameter to ``true``.
.. code-block:: bash
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export SERVER_URL=https://demo.dataverse.org
export FILE_ID=42
export DATASET_VERSION=:draft
export INCLUDE_DEACCESSIONED=true
curl -H "X-Dataverse-key:$API_TOKEN" "$SERVER_URL/api/files/$FILE_ID/versions/$DATASET_VERSION/citation?includeDeaccessioned=$INCLUDE_DEACCESSIONED"
The fully expanded example above (without environment variables) looks like this:
.. code-block:: bash
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" "https://demo.dataverse.org/api/files/42/versions/:draft/citation?includeDeaccessioned=true"
If your file has a persistent identifier (PID, such as a DOI), you can pass it using the technique described under :ref:`get-json-rep-of-file`.
This API is not for downloading various citation formats such as EndNote XML, RIS, or BibTeX. This functionality has been requested in https://github.com/IQSS/dataverse/issues/3140 and https://github.com/IQSS/dataverse/issues/9994.
Provenance
~~~~~~~~~~
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import edu.harvard.iq.dataverse.*;
import edu.harvard.iq.dataverse.actionlogging.ActionLogServiceBean;
import static edu.harvard.iq.dataverse.api.Datasets.handleVersion;
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.DataverseRole;
import edu.harvard.iq.dataverse.authorization.RoleAssignee;
Expand All @@ -15,6 +16,10 @@
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException;
import edu.harvard.iq.dataverse.engine.command.exception.PermissionException;
import edu.harvard.iq.dataverse.engine.command.impl.GetDraftDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetLatestAccessibleDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetLatestPublishedDatasetVersionCommand;
import edu.harvard.iq.dataverse.engine.command.impl.GetSpecificPublishedDatasetVersionCommand;
import edu.harvard.iq.dataverse.externaltools.ExternalToolServiceBean;
import edu.harvard.iq.dataverse.license.LicenseServiceBean;
import edu.harvard.iq.dataverse.locality.StorageSiteServiceBean;
Expand Down Expand Up @@ -390,6 +395,32 @@ protected Dataset findDatasetOrDie(String id) throws WrappedResponse {
}
}
}

protected DatasetVersion findDatasetVersionOrDie(final DataverseRequest req, String versionNumber, final Dataset ds, boolean includeDeaccessioned, boolean checkPermsWhenDeaccessioned) throws WrappedResponse {
DatasetVersion dsv = execCommand(handleVersion(versionNumber, new Datasets.DsVersionHandler<Command<DatasetVersion>>() {

@Override
public Command<DatasetVersion> handleLatest() {
return new GetLatestAccessibleDatasetVersionCommand(req, ds, includeDeaccessioned, checkPermsWhenDeaccessioned);
}

@Override
public Command<DatasetVersion> handleDraft() {
return new GetDraftDatasetVersionCommand(req, ds);
}

@Override
public Command<DatasetVersion> handleSpecific(long major, long minor) {
return new GetSpecificPublishedDatasetVersionCommand(req, ds, major, minor, includeDeaccessioned, checkPermsWhenDeaccessioned);
}

@Override
public Command<DatasetVersion> handleLatestPublished() {
return new GetLatestPublishedDatasetVersionCommand(req, ds, includeDeaccessioned, checkPermsWhenDeaccessioned);
}
}));
return dsv;
}

protected DataFile findDataFileOrDie(String id) throws WrappedResponse {

Expand Down
23 changes: 1 addition & 22 deletions src/main/java/edu/harvard/iq/dataverse/api/Datasets.java
Original file line number Diff line number Diff line change
Expand Up @@ -2727,28 +2727,7 @@ private DatasetVersion getDatasetVersionOrDie(final DataverseRequest req, String
* Will allow to define when the permissions should be checked when a deaccesioned dataset is requested. If the user doesn't have edit permissions will result in an error.
*/
private DatasetVersion getDatasetVersionOrDie(final DataverseRequest req, String versionNumber, final Dataset ds, UriInfo uriInfo, HttpHeaders headers, boolean includeDeaccessioned, boolean checkPermsWhenDeaccessioned) throws WrappedResponse {
DatasetVersion dsv = execCommand(handleVersion(versionNumber, new DsVersionHandler<Command<DatasetVersion>>() {

@Override
public Command<DatasetVersion> handleLatest() {
return new GetLatestAccessibleDatasetVersionCommand(req, ds, includeDeaccessioned, checkPermsWhenDeaccessioned);
}

@Override
public Command<DatasetVersion> handleDraft() {
return new GetDraftDatasetVersionCommand(req, ds);
}

@Override
public Command<DatasetVersion> handleSpecific(long major, long minor) {
return new GetSpecificPublishedDatasetVersionCommand(req, ds, major, minor, includeDeaccessioned, checkPermsWhenDeaccessioned);
}

@Override
public Command<DatasetVersion> handleLatestPublished() {
return new GetLatestPublishedDatasetVersionCommand(req, ds, includeDeaccessioned, checkPermsWhenDeaccessioned);
}
}));
DatasetVersion dsv = findDatasetVersionOrDie(req, versionNumber, ds, includeDeaccessioned, checkPermsWhenDeaccessioned);
if (dsv == null || dsv.getId() == null) {
throw new WrappedResponse(notFound("Dataset version " + versionNumber + " of dataset " + ds.getId() + " not found"));
}
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/Files.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import edu.harvard.iq.dataverse.DataCitation;
import edu.harvard.iq.dataverse.DataFile;
import edu.harvard.iq.dataverse.DataFileServiceBean;
import edu.harvard.iq.dataverse.DataFileTag;
Expand All @@ -27,6 +28,7 @@
import edu.harvard.iq.dataverse.datasetutility.DataFileTagException;
import edu.harvard.iq.dataverse.datasetutility.NoFilesException;
import edu.harvard.iq.dataverse.datasetutility.OptionalFileParams;
import edu.harvard.iq.dataverse.engine.command.Command;
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException;
Expand Down Expand Up @@ -931,4 +933,37 @@ public Response getHasBeenDeleted(@Context ContainerRequestContext crc, @PathPar
return ok(dataFileServiceBean.hasBeenDeleted(dataFile));
}, getRequestUser(crc));
}

/**
* @param fileIdOrPersistentId Database ID or PID of the data file.
* @param versionNumber The version of the dataset, such as 1.0, :draft,
* :latest-published, etc.
* @param includeDeaccessioned Defaults to false.
*/
@GET
@AuthRequired
@Path("{id}/versions/{dsVersionString}/citation")
public Response getFileCitationByVersion(@Context ContainerRequestContext crc, @PathParam("id") String fileIdOrPersistentId, @PathParam("dsVersionString") String versionNumber, @QueryParam("includeDeaccessioned") boolean includeDeaccessioned) {
try {
DataverseRequest req = createDataverseRequest(getRequestUser(crc));
final DataFile df = execCommand(new GetDataFileCommand(req, findDataFileOrDie(fileIdOrPersistentId)));
Dataset ds = df.getOwner();
DatasetVersion dsv = findDatasetVersionOrDie(req, versionNumber, ds, includeDeaccessioned, true);
if (dsv == null) {
return unauthorized(BundleUtil.getStringFromBundle("files.api.no.draftOrUnauth"));
}

Long getDatasetVersionID = dsv.getId();
FileMetadata fm = dataFileServiceBean.findFileMetadataByDatasetVersionIdAndDataFileId(getDatasetVersionID, df.getId());
if (fm == null) {
return notFound(BundleUtil.getStringFromBundle("files.api.fileNotFound"));
}
boolean direct = df.isIdentifierRegistered();
DataCitation citation = new DataCitation(fm, direct);
return ok(citation.toString(true));
} catch (WrappedResponse ex) {
return ex.getResponse();
}
}

}
2 changes: 2 additions & 0 deletions src/main/java/propertyFiles/Bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2633,7 +2633,9 @@ admin.api.deleteUser.success=Authenticated User {0} deleted.
#Files.java
files.api.metadata.update.duplicateFile=Filename already exists at {0}
files.api.no.draft=No draft available for this file
files.api.no.draftOrUnauth=Dataset version cannot be found or unauthorized.
files.api.only.tabular.supported=This operation is only available for tabular files.
files.api.fileNotFound=File could not be found.

#Datasets.java
datasets.api.updatePIDMetadata.failure.dataset.must.be.released=Modify Registration Metadata must be run on a published dataset.
Expand Down
31 changes: 31 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/DataCitationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,36 @@ public void testTitleWithQuotes() throws ParseException {

}

@Test
public void testFileCitationToStringHtml() throws ParseException {
DatasetVersion dsv = createATestDatasetVersion("Dataset Title", true);
FileMetadata fileMetadata = new FileMetadata();
fileMetadata.setLabel("foo.txt");
fileMetadata.setDataFile(new DataFile());
dsv.setVersionState(DatasetVersion.VersionState.RELEASED);
fileMetadata.setDatasetVersion(dsv);
dsv.setDataset(dsv.getDataset());
DataCitation fileCitation = new DataCitation(fileMetadata, false);
assertEquals("First Last, 1955, \"Dataset Title\", <a href=\"https://doi.org/10.5072/FK2/LK0D1H\" target=\"_blank\">https://doi.org/10.5072/FK2/LK0D1H</a>, LibraScholar, V1; foo.txt [fileName]", fileCitation.toString(true));
}

@Test
public void testFileCitationToStringHtmlFilePid() throws ParseException {
DatasetVersion dsv = createATestDatasetVersion("Dataset Title", true);
FileMetadata fileMetadata = new FileMetadata();
fileMetadata.setLabel("foo.txt");
DataFile dataFile = new DataFile();
dataFile.setProtocol("doi");
dataFile.setAuthority("10.42");
dataFile.setIdentifier("myFilePid");
fileMetadata.setDataFile(dataFile);
dsv.setVersionState(DatasetVersion.VersionState.RELEASED);
fileMetadata.setDatasetVersion(dsv);
dsv.setDataset(dsv.getDataset());
DataCitation fileCitation = new DataCitation(fileMetadata, true);
assertEquals("First Last, 1955, \"foo.txt\", <em>Dataset Title</em>, <a href=\"https://doi.org/10.42/myFilePid\" target=\"_blank\">https://doi.org/10.42/myFilePid</a>, LibraScholar, V1", fileCitation.toString(true));
}

private DatasetVersion createATestDatasetVersion(String withTitle, boolean withAuthor) throws ParseException {

Dataverse dataverse = new Dataverse();
Expand All @@ -400,6 +430,7 @@ private DatasetVersion createATestDatasetVersion(String withTitle, boolean withA
fields.add(createTitleField(withTitle));
}
if (withAuthor) {
// TODO: "Last, First" would make more sense.
fields.add(createAuthorField("First Last"));
}

Expand Down
Loading

0 comments on commit 82585f9

Please sign in to comment.