Skip to content

Commit e69cf6f

Browse files
authored
Merge pull request #11565 from IQSS/11562-api-get-templates
Get Dataverse templates API endpoints
2 parents f2f9d05 + 522fd2f commit e69cf6f

File tree

17 files changed

+693
-23
lines changed

17 files changed

+693
-23
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
New endpoints have been implemented in the Dataverses API for the management of dataverse templates:
2+
3+
- POST `/dataverses/{id}/templates`: Creates a template for a given Dataverse collection ``id``.
4+
- GET `/dataverses/{id}/templates`: Lists the templates for a given Dataverse collection ``id``.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "Dataverse template",
3+
"isDefault": true,
4+
"fields": [
5+
{
6+
"typeName": "author",
7+
"value": [
8+
{
9+
"authorName": {
10+
"typeName": "authorName",
11+
"value": "Belicheck, Bill"
12+
},
13+
"authorAffiliation": {
14+
"typeName": "authorIdentifierScheme",
15+
"value": "ORCID"
16+
}
17+
}
18+
]
19+
}
20+
],
21+
"instructions": [
22+
{
23+
"instructionField": "author",
24+
"instructionText": "The author data"
25+
}
26+
]
27+
}

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,46 @@ The fully expanded example above (without environment variables) looks like this
14001400
14011401
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X GET "https://demo.dataverse.org/api/access/dataverseFeaturedItemImage/1"
14021402
1403+
List Templates of a Collection
1404+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1405+
1406+
Lists the templates for a given Dataverse collection ``id``:
1407+
1408+
.. code-block:: bash
1409+
1410+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
1411+
export SERVER_URL=https://demo.dataverse.org
1412+
export ID=1
1413+
1414+
curl -H "X-Dataverse-key:$API_TOKEN" -X GET "$SERVER_URL/api/dataverses/{ID}/templates"
1415+
1416+
The fully expanded example above (without environment variables) looks like this:
1417+
1418+
.. code-block:: bash
1419+
1420+
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X GET "https://demo.dataverse.org/api/dataverses/1/templates"
1421+
1422+
Create a Template for a Collection
1423+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1424+
1425+
Creates a template for a given Dataverse collection ``id``.
1426+
1427+
To create the template, you must send a JSON file. Your JSON file might look like :download:`dataverse-template.json <../_static/api/dataverse-template.json>` which you would send to the Dataverse installation like this:
1428+
1429+
.. code-block:: bash
1430+
1431+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
1432+
export SERVER_URL=https://demo.dataverse.org
1433+
export ID=1
1434+
1435+
curl -H "X-Dataverse-key: $API_TOKEN" -X POST "$SERVER_URL/api/dataverses/{ID}/templates" --upload-file dataverse-template.json
1436+
1437+
The fully expanded example above (without environment variables) looks like this:
1438+
1439+
.. code-block:: bash
1440+
1441+
curl -H "X-Dataverse-key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X POST "https://demo.dataverse.org/api/dataverses/1/templates" --upload-file dataverse-template.json
1442+
14031443
Datasets
14041444
--------
14051445

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
77
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean;
88
import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItemServiceBean;
9+
import edu.harvard.iq.dataverse.license.LicenseServiceBean;
910
import edu.harvard.iq.dataverse.util.cache.CacheFactoryBean;
1011
import edu.harvard.iq.dataverse.engine.DataverseEngine;
1112
import edu.harvard.iq.dataverse.authorization.Permission;
@@ -192,6 +193,9 @@ public class EjbDataverseEngine {
192193
@EJB
193194
DataverseFeaturedItemServiceBean dataverseFeaturedItemServiceBean;
194195

196+
@EJB
197+
LicenseServiceBean licenseServiceBean;
198+
195199
@EJB
196200
DatasetFieldsValidator datasetFieldsValidator;
197201

@@ -541,6 +545,11 @@ public DatasetFieldsValidator datasetFieldsValidator() {
541545
return datasetFieldsValidator;
542546
}
543547

548+
@Override
549+
public LicenseServiceBean licenses() {
550+
return licenseServiceBean;
551+
}
552+
544553
@Override
545554
public StorageUseServiceBean storageUse() {
546555
return storageUseService;

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ public List<DatasetField> getDatasetFields() {
137137

138138
@Transient
139139
private Map<String, String> instructionsMap = null;
140-
140+
141+
public void setInstructionsMap(Map<String, String> instructionsMap) {
142+
this.instructionsMap = instructionsMap;
143+
}
144+
141145
@Transient
142146
private TreeMap<MetadataBlock, List<DatasetField>> metadataBlocksForView = new TreeMap<>();
143147
@Transient

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,4 +1931,34 @@ public Response deleteFeaturedItems(@Context ContainerRequestContext crc, @PathP
19311931
return e.getResponse();
19321932
}
19331933
}
1934+
1935+
@GET
1936+
@AuthRequired
1937+
@Path("{identifier}/templates")
1938+
public Response getTemplates(@Context ContainerRequestContext crc, @PathParam("identifier") String dvIdtf) {
1939+
try {
1940+
Dataverse dataverse = findDataverseOrDie(dvIdtf);
1941+
return ok(jsonTemplates(execCommand(new ListDataverseTemplatesCommand(createDataverseRequest(getRequestUser(crc)), dataverse))));
1942+
} catch (WrappedResponse e) {
1943+
return e.getResponse();
1944+
}
1945+
}
1946+
1947+
@POST
1948+
@AuthRequired
1949+
@Path("{identifier}/templates")
1950+
public Response createTemplate(@Context ContainerRequestContext crc, String body, @PathParam("identifier") String dvIdtf) {
1951+
try {
1952+
Dataverse dataverse = findDataverseOrDie(dvIdtf);
1953+
NewTemplateDTO newTemplateDTO;
1954+
try {
1955+
newTemplateDTO = NewTemplateDTO.fromRequestBody(body, jsonParser());
1956+
} catch (JsonParseException ex) {
1957+
return error(Status.BAD_REQUEST, MessageFormat.format(BundleUtil.getStringFromBundle("dataverse.createTemplate.error.jsonParseMetadataFields"), ex.getMessage()));
1958+
}
1959+
return ok(jsonTemplate(execCommand(new CreateTemplateCommand(newTemplateDTO.toTemplate(), createDataverseRequest(getRequestUser(crc)), dataverse, true))));
1960+
} catch (WrappedResponse e) {
1961+
return e.getResponse();
1962+
}
1963+
}
19341964
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package edu.harvard.iq.dataverse.api.dto;
2+
3+
import edu.harvard.iq.dataverse.*;
4+
import edu.harvard.iq.dataverse.util.json.JsonParseException;
5+
import edu.harvard.iq.dataverse.util.json.JsonParser;
6+
import edu.harvard.iq.dataverse.util.json.JsonUtil;
7+
import jakarta.json.*;
8+
9+
import java.sql.Timestamp;
10+
import java.util.*;
11+
12+
public class NewTemplateDTO {
13+
14+
private String name;
15+
private List<DatasetField> datasetFields;
16+
private Map<String, String> instructionsMap;
17+
private boolean isDefault;
18+
19+
public static NewTemplateDTO fromRequestBody(String requestBody, JsonParser jsonParser) throws JsonParseException {
20+
NewTemplateDTO newTemplateDTO = new NewTemplateDTO();
21+
22+
JsonObject jsonObject = JsonUtil.getJsonObject(requestBody);
23+
24+
newTemplateDTO.name = jsonObject.getString("name");
25+
newTemplateDTO.datasetFields = jsonParser.parseMultipleFields(jsonObject);
26+
newTemplateDTO.instructionsMap = parseRequestBodyInstructionsMap(jsonObject);
27+
newTemplateDTO.isDefault = jsonObject.getBoolean("isDefault", false);
28+
29+
return newTemplateDTO;
30+
}
31+
32+
public Template toTemplate() {
33+
Template template = new Template();
34+
35+
template.setDatasetFields(getDatasetFields());
36+
template.setName(getName());
37+
template.setInstructionsMap(getInstructionsMap());
38+
template.updateInstructions();
39+
template.setCreateTime(new Timestamp(new Date().getTime()));
40+
template.setUsageCount(0L);
41+
42+
return template;
43+
}
44+
45+
public String getName() {
46+
return name;
47+
}
48+
49+
public List<DatasetField> getDatasetFields() {
50+
return datasetFields;
51+
}
52+
53+
public Map<String, String> getInstructionsMap() {
54+
return instructionsMap;
55+
}
56+
57+
public boolean isDefault() {
58+
return isDefault;
59+
}
60+
61+
private static Map<String, String> parseRequestBodyInstructionsMap(JsonObject jsonObject) {
62+
Map<String, String> instructionsMap = new HashMap<>();
63+
JsonArray instructionsJsonArray = jsonObject.getJsonArray("instructions");
64+
if (instructionsJsonArray == null) {
65+
return null;
66+
}
67+
for (JsonObject instructionJsonObject : instructionsJsonArray.getValuesAs(JsonObject.class)) {
68+
instructionsMap.put(
69+
instructionJsonObject.getString("instructionField"),
70+
instructionJsonObject.getString("instructionText")
71+
);
72+
}
73+
return instructionsMap;
74+
}
75+
}

src/main/java/edu/harvard/iq/dataverse/engine/command/CommandContext.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import edu.harvard.iq.dataverse.dataset.DatasetFieldsValidator;
55
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean;
66
import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItemServiceBean;
7+
import edu.harvard.iq.dataverse.license.LicenseServiceBean;
78
import edu.harvard.iq.dataverse.search.IndexServiceBean;
89
import edu.harvard.iq.dataverse.search.SearchService;
910
import edu.harvard.iq.dataverse.search.SearchServiceFactory;
@@ -140,4 +141,6 @@ public interface CommandContext {
140141
public DataverseFeaturedItemServiceBean dataverseFeaturedItems();
141142

142143
public DatasetFieldsValidator datasetFieldsValidator();
144+
145+
public LicenseServiceBean licenses();
143146
}
Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,88 @@
1-
21
package edu.harvard.iq.dataverse.engine.command.impl;
3-
import edu.harvard.iq.dataverse.Dataverse;
4-
import edu.harvard.iq.dataverse.Template;
2+
3+
import edu.harvard.iq.dataverse.*;
54
import edu.harvard.iq.dataverse.authorization.Permission;
65

76
import edu.harvard.iq.dataverse.engine.command.AbstractCommand;
87
import edu.harvard.iq.dataverse.engine.command.CommandContext;
98
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
109
import edu.harvard.iq.dataverse.engine.command.RequiredPermissions;
1110
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
11+
import edu.harvard.iq.dataverse.settings.JvmSettings;
12+
import edu.harvard.iq.dataverse.util.DatasetFieldUtil;
13+
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
1217
/**
13-
*
1418
* @author skraffmiller
19+
* Creates a template {@link Template} for a {@link Dataverse}.
1520
*/
16-
@RequiredPermissions( Permission.EditDataverse )
21+
@RequiredPermissions(Permission.EditDataverse)
1722
public class CreateTemplateCommand extends AbstractCommand<Template> {
18-
private final Template created;
19-
private final Dataverse dv;
20-
21-
public CreateTemplateCommand(Template template, DataverseRequest aRequest, Dataverse anAffectedDataverse) {
22-
super(aRequest, anAffectedDataverse);
23-
created = template;
24-
dv = anAffectedDataverse;
25-
}
26-
27-
@Override
28-
public Template execute(CommandContext ctxt) throws CommandException {
29-
30-
return ctxt.templates().save(created);
31-
}
32-
23+
private final Template template;
24+
private final Dataverse dataverse;
25+
26+
private final boolean initialize;
27+
28+
public CreateTemplateCommand(Template template, DataverseRequest request, Dataverse dataverse) {
29+
this(template, request, dataverse, false);
30+
}
31+
32+
public CreateTemplateCommand(Template template, DataverseRequest request, Dataverse dataverse, boolean initialize) {
33+
super(request, dataverse);
34+
this.template = template;
35+
this.dataverse = dataverse;
36+
this.initialize = initialize;
37+
}
38+
39+
@Override
40+
public Template execute(CommandContext ctxt) throws CommandException {
41+
if (initialize) {
42+
template.setDataverse(dataverse);
43+
template.setMetadataValueBlocks(getSystemMetadataBlocks(ctxt));
44+
45+
updateTermsOfUseAndAccess(ctxt, template);
46+
updateDatasetFieldInputLevels(template, ctxt);
47+
48+
DatasetFieldUtil.tidyUpFields(template.getDatasetFields(), false);
49+
}
50+
51+
return ctxt.templates().save(template);
52+
}
53+
54+
private static void updateTermsOfUseAndAccess(CommandContext ctxt, Template template) {
55+
TermsOfUseAndAccess terms = new TermsOfUseAndAccess();
56+
terms.setFileAccessRequest(true);
57+
terms.setTemplate(template);
58+
terms.setLicense(ctxt.licenses().getDefault());
59+
template.setTermsOfUseAndAccess(terms);
60+
}
61+
62+
private void updateDatasetFieldInputLevels(Template template, CommandContext ctxt) {
63+
Long dvIdForInputLevel = this.dataverse.getId();
64+
if (!this.dataverse.isMetadataBlockRoot()) {
65+
dvIdForInputLevel = this.dataverse.getMetadataRootId();
66+
}
67+
68+
for (DatasetField dsf : template.getFlatDatasetFields()) {
69+
DataverseFieldTypeInputLevel inputLevel = ctxt.fieldTypeInputLevels().findByDataverseIdDatasetFieldTypeId(
70+
dvIdForInputLevel,
71+
dsf.getDatasetFieldType().getId()
72+
);
73+
if (inputLevel != null) {
74+
dsf.setInclude(inputLevel.isInclude());
75+
} else {
76+
dsf.setInclude(true);
77+
}
78+
}
79+
}
80+
81+
private static List<MetadataBlock> getSystemMetadataBlocks(CommandContext ctxt) {
82+
List<MetadataBlock> systemMetadataBlocks = new ArrayList<>();
83+
for (MetadataBlock mdb : ctxt.metadataBlocks().listMetadataBlocks()) {
84+
JvmSettings.MDB_SYSTEM_KEY_FOR.lookupOptional(mdb.getName()).ifPresent(smdbString -> systemMetadataBlocks.add(mdb));
85+
}
86+
return systemMetadataBlocks;
87+
}
3388
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package edu.harvard.iq.dataverse.engine.command.impl;
2+
3+
import edu.harvard.iq.dataverse.Dataverse;
4+
import edu.harvard.iq.dataverse.Template;
5+
import edu.harvard.iq.dataverse.authorization.Permission;
6+
import edu.harvard.iq.dataverse.engine.command.AbstractCommand;
7+
import edu.harvard.iq.dataverse.engine.command.CommandContext;
8+
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
9+
import edu.harvard.iq.dataverse.engine.command.RequiredPermissions;
10+
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
11+
12+
import java.util.*;
13+
14+
/**
15+
* Lists the templates {@link Template} of a {@link Dataverse}.
16+
*/
17+
@RequiredPermissions(Permission.EditDataverse)
18+
public class ListDataverseTemplatesCommand extends AbstractCommand<List<Template>> {
19+
20+
private final Dataverse dataverse;
21+
22+
public ListDataverseTemplatesCommand(DataverseRequest request, Dataverse dataverse) {
23+
super(request, dataverse);
24+
this.dataverse = dataverse;
25+
}
26+
27+
@Override
28+
public List<Template> execute(CommandContext ctxt) throws CommandException {
29+
List<Template> templates = new ArrayList<>();
30+
31+
if (dataverse.getOwner() != null) {
32+
templates.addAll(dataverse.getParentTemplates());
33+
}
34+
35+
templates.addAll(dataverse.getTemplates());
36+
37+
return templates;
38+
}
39+
}

0 commit comments

Comments
 (0)