Skip to content

Commit f1320c1

Browse files
committed
new api to get formatted datafile citations
1 parent 27e1f1f commit f1320c1

7 files changed

Lines changed: 154 additions & 37 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
### Feature New API ###
2+
New API added to retrieve the DataFile Citation in a requested format. This is similar output to the API to get the Dataset Citation.
3+
4+
SERVER_URL/api/access/datafile/{fileId}/citation/{format}

doc/sphinx-guides/source/api/dataaccess.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,26 @@ Value Description
254254
ID Exports file with specific file metadata ``ID``.
255255
============== ===========
256256

257+
258+
.. _datafile-citation-formatted-access:
259+
260+
Citation - Get Citation In Other Formats
261+
----------------------------------------
262+
263+
Dataverse can generate datafile citations in "EndNote", "RIS", "BibTeX", and "CSL" formats.
264+
This API call sends the raw format with the appropriate content-type (EndNote is XML, RIS and BibTeX are plain text, and CSL is JSON). ("Internal" is also a valid value, returning the content as HTML).
265+
This API call requires a format in the API call which can be any of the values listed above.
266+
267+
Usage example:
268+
269+
.. code-block:: bash
270+
271+
export SERVER_URL=https://demo.dataverse.org
272+
export DATAFILE_ID=99
273+
export FORMAT=EndNote
274+
275+
curl "$SERVER_URL/api/access/datafile/$DATAFILE_ID/citation/$FORMAT"
276+
257277
.. _data-variable-metadata-access:
258278

259279
Data Variable Metadata Access

doc/sphinx-guides/source/api/native-api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4095,6 +4095,8 @@ Usage example:
40954095
40964096
The type under CSL can vary based on the dataset type, with "dataset", "software", and "review" as supported values. See also :ref:`dataset-types`.
40974097

4098+
.. note:: You can also get the Datafile Citation by using the Access Datafile API. See: :ref:`datafile-citation-formatted-access`.
4099+
40984100
Get Citation by Preview URL Token
40994101
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41004102

src/main/java/edu/harvard/iq/dataverse/DataCitation.java

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,55 +5,40 @@
55
*/
66
package edu.harvard.iq.dataverse;
77

8+
import de.undercouch.citeproc.csl.CSLItemDataBuilder;
9+
import de.undercouch.citeproc.csl.CSLName;
10+
import de.undercouch.citeproc.csl.CSLNameBuilder;
11+
import de.undercouch.citeproc.csl.CSLType;
12+
import de.undercouch.citeproc.helper.json.JsonBuilder;
13+
import de.undercouch.citeproc.helper.json.StringJsonBuilderFactory;
814
import edu.harvard.iq.dataverse.branding.BrandingUtil;
915
import edu.harvard.iq.dataverse.dataset.DatasetType;
1016
import edu.harvard.iq.dataverse.harvest.client.HarvestingClient;
1117
import edu.harvard.iq.dataverse.pidproviders.AbstractPidProvider;
18+
import edu.harvard.iq.dataverse.util.BundleUtil;
19+
import edu.harvard.iq.dataverse.util.DateUtil;
20+
import edu.harvard.iq.dataverse.util.PersonOrOrgUtil;
21+
import edu.harvard.iq.dataverse.util.SystemConfig;
22+
import edu.harvard.iq.dataverse.util.json.JsonUtil;
23+
import jakarta.ejb.EJBException;
24+
import jakarta.json.JsonObject;
25+
import jakarta.ws.rs.core.MediaType;
26+
import org.apache.commons.lang3.StringUtils;
27+
import org.apache.commons.text.StringEscapeUtils;
1228

13-
import java.io.BufferedWriter;
14-
import java.io.ByteArrayOutputStream;
15-
import java.io.IOException;
16-
import java.io.OutputStream;
17-
import java.io.OutputStreamWriter;
18-
import java.io.Writer;
29+
import javax.xml.stream.XMLOutputFactory;
30+
import javax.xml.stream.XMLStreamException;
31+
import javax.xml.stream.XMLStreamWriter;
32+
import java.io.*;
1933
import java.nio.charset.StandardCharsets;
2034
import java.text.SimpleDateFormat;
21-
import java.util.ArrayList;
22-
import java.util.Date;
23-
import java.util.HashMap;
24-
import java.util.List;
25-
import java.util.Map;
35+
import java.util.*;
2636
import java.util.logging.Level;
2737
import java.util.logging.Logger;
2838
import java.util.regex.Matcher;
2939
import java.util.regex.Pattern;
3040
import java.util.stream.Collectors;
3141

32-
import jakarta.ejb.EJBException;
33-
import jakarta.json.JsonObject;
34-
import jakarta.ws.rs.core.MediaType;
35-
36-
import javax.xml.stream.XMLOutputFactory;
37-
import javax.xml.stream.XMLStreamException;
38-
import javax.xml.stream.XMLStreamWriter;
39-
40-
import edu.harvard.iq.dataverse.util.BundleUtil;
41-
import edu.harvard.iq.dataverse.util.DateUtil;
42-
import edu.harvard.iq.dataverse.util.PersonOrOrgUtil;
43-
import edu.harvard.iq.dataverse.util.SystemConfig;
44-
import edu.harvard.iq.dataverse.util.json.JsonUtil;
45-
46-
import org.apache.commons.text.StringEscapeUtils;
47-
48-
import de.undercouch.citeproc.csl.CSLItemDataBuilder;
49-
import de.undercouch.citeproc.csl.CSLName;
50-
import de.undercouch.citeproc.csl.CSLNameBuilder;
51-
import de.undercouch.citeproc.csl.CSLType;
52-
import de.undercouch.citeproc.helper.json.JsonBuilder;
53-
import de.undercouch.citeproc.helper.json.StringJsonBuilderFactory;
54-
55-
import org.apache.commons.lang3.StringUtils;
56-
5742
import static edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider.DOI_PROTOCOL;
5843
import static edu.harvard.iq.dataverse.pidproviders.handle.HandlePidProvider.HDL_PROTOCOL;
5944
import static edu.harvard.iq.dataverse.pidproviders.perma.PermaLinkPidProvider.PERMA_PROTOCOL;
@@ -99,6 +84,15 @@ public enum Format {
9984
BibTeX,
10085
CSL
10186
}
87+
88+
public static Format getFormat(String name) {
89+
for (Format format : Format.values()) {
90+
if (format.name().equalsIgnoreCase(name)) {
91+
return format;
92+
}
93+
}
94+
return null;
95+
}
10296

10397
public DataCitation(DatasetVersion dsv) {
10498
this(dsv, false);

src/main/java/edu/harvard/iq/dataverse/api/Access.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,29 @@ public class Access extends AbstractApiBean {
130130

131131
private static final String DEFAULT_BUNDLE_NAME = "dataverse_files.zip";
132132
//@EJB
133-
133+
134+
@GET
135+
@AuthRequired
136+
@Path("datafile/{fileId}/citation/{format}")
137+
public Response datafileCitation(@Context ContainerRequestContext crc,
138+
@PathParam("fileId") String fileId,
139+
@PathParam("format") String formatString) {
140+
141+
DataCitation.Format format = DataCitation.getFormat(formatString);
142+
if (format == null) {
143+
return badRequest(BundleUtil.getStringFromBundle("datasets.api.citation.invalidFormat"));
144+
}
145+
146+
DataFile df = findDataFileOrDieWrapper(fileId);
147+
148+
// This will throw a ForbiddenException if access isn't authorized:
149+
checkAuthorization(crc, df);
150+
151+
String dataCitationFormatted = (new DataCitation(df.getFileMetadata())).toString(format, true, false);
152+
153+
return Response.ok().type(DataCitation.getCitationFormatMediaType(format, true)).entity(dataCitationFormatted).build();
154+
}
155+
134156
// TODO:
135157
// versions? -- L.A. 4.0 beta 10
136158
@GET

src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4060,4 +4060,73 @@ public void testDownloadFileWithGuestbookResponse() throws IOException, JsonPars
40604060
signedUrlResponse = get(signedUrl);
40614061
assertEquals(OK.getStatusCode(), signedUrlResponse.getStatusCode());
40624062
}
4063+
4064+
@Test
4065+
public void testGetFileCitationFormatted() {
4066+
Response createUser = UtilIT.createRandomUser();
4067+
createUser.then().assertThat().statusCode(OK.getStatusCode());
4068+
String apiToken = UtilIT.getApiTokenFromResponse(createUser);
4069+
4070+
Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
4071+
createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode());
4072+
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
4073+
4074+
Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken);
4075+
createDatasetResponse.then().assertThat().statusCode(CREATED.getStatusCode());
4076+
Integer datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id");
4077+
4078+
String pathToTestFile = "src/test/resources/images/coffeeshop.png";
4079+
Response uploadFile = UtilIT.uploadFileViaNative(datasetId.toString(), pathToTestFile, Json.createObjectBuilder().build(), apiToken);
4080+
uploadFile.then().assertThat().statusCode(OK.getStatusCode());
4081+
4082+
String fileId = JsonPath.from(uploadFile.body().asString()).getString("data.files[0].dataFile.id");
4083+
4084+
// Test good formats
4085+
Response response = UtilIT.getFileCitationFormat(fileId,"EndNote", apiToken);
4086+
response.then().assertThat()
4087+
.statusCode(OK.getStatusCode());
4088+
assertTrue(response.prettyPrint().contains("<custom1>coffeeshop.png</custom1>"));
4089+
4090+
response = UtilIT.getFileCitationFormat(fileId,"RIS", apiToken);
4091+
response.then().assertThat()
4092+
.statusCode(OK.getStatusCode());
4093+
assertTrue(response.prettyPrint().contains("C1 - coffeeshop.png"));
4094+
4095+
response = UtilIT.getFileCitationFormat(fileId,"BibTeX", apiToken);
4096+
response.then().assertThat()
4097+
.statusCode(OK.getStatusCode());
4098+
assertTrue(response.prettyPrint().contains("author = {Finch, Fiona},"));
4099+
4100+
response = UtilIT.getFileCitationFormat(fileId,"CSL", apiToken);
4101+
response.then().assertThat()
4102+
.statusCode(OK.getStatusCode());
4103+
assertTrue(response.prettyPrint().contains("\"title\": \"Darwin's Finches\","));
4104+
4105+
response = UtilIT.getFileCitationFormat(fileId,"Internal", apiToken);
4106+
response.then().assertThat()
4107+
.statusCode(OK.getStatusCode());
4108+
assertTrue(response.prettyPrint().contains("coffeeshop.png [fileName]"));
4109+
4110+
// Test an unknown format
4111+
response = UtilIT.getFileCitationFormat(fileId,"bad", apiToken);
4112+
response.prettyPrint();
4113+
response.then().assertThat()
4114+
.statusCode(BAD_REQUEST.getStatusCode())
4115+
.body("message", equalTo(BundleUtil.getStringFromBundle("datasets.api.citation.invalidFormat")));
4116+
// Test an NULL format
4117+
response = UtilIT.getFileCitationFormat(fileId,null, apiToken);
4118+
response.prettyPrint();
4119+
response.then().assertThat()
4120+
.statusCode(BAD_REQUEST.getStatusCode())
4121+
.body("message", equalTo(BundleUtil.getStringFromBundle("datasets.api.citation.invalidFormat")));
4122+
4123+
// Test a user that doesn't have permission to get the citation
4124+
Response createUser2 = UtilIT.createRandomUser();
4125+
createUser2.then().assertThat().statusCode(OK.getStatusCode());
4126+
String apiToken2 = UtilIT.getApiTokenFromResponse(createUser2);
4127+
response = UtilIT.getFileCitationFormat(fileId,"EndNote",apiToken2);
4128+
response.prettyPrint();
4129+
response.then().assertThat()
4130+
.statusCode(FORBIDDEN.getStatusCode());
4131+
}
40634132
}

src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,12 @@ static Response getFileData(String fileId, String apiToken, String datasetVersio
14431443
.get("/api/files/" + fileId + "/versions/" + datasetVersionId);
14441444
}
14451445

1446+
static Response getFileCitationFormat(String dataFileId, String format, String apiToken) {
1447+
return given()
1448+
.header(API_TOKEN_HTTP_HEADER, apiToken)
1449+
.get("/api/access/datafile/" + dataFileId + "/citation/" + format);
1450+
}
1451+
14461452
static Response getFileVersionDifferences(String fileId, String apiToken) {
14471453
return getFileVersionDifferences(fileId, apiToken, null, null);
14481454
}

0 commit comments

Comments
 (0)