Skip to content

Commit 954697d

Browse files
authored
Merge pull request #11969 from IQSS/11918-template-apis
11918 template apis
2 parents bceddc2 + 1c241ee commit 954697d

File tree

9 files changed

+348
-10
lines changed

9 files changed

+348
-10
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## New Endpoint: GET `/dataverses/{id}/template`
2+
3+
A new endpoint has been implemented to manage templates belonging to a given dataverse collection.
4+
5+
### Functionality
6+
- Returns the template of the given {id} in json format.
7+
- You must have add dataset permission in the collection in order to use this endpoint.
8+
9+
## New Endpoint: DELETE `/dataverses/{id}/template`
10+
11+
A new endpoint has been implemented to manage templates belonging to a given dataverse collection.
12+
13+
### Functionality
14+
- Deletes the template of the given {id}.
15+
- You must have Edit Dataverse permission in order to use this endpoint.
16+
17+

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,6 +1576,48 @@ The fully expanded example above (without environment variables) looks like this
15761576
15771577
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X GET "https://demo.dataverse.org/api/dataverses/1/templates"
15781578
1579+
List Single Template by its Identifier
1580+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1581+
1582+
Gets the json representation of a template by its ``id``:
1583+
1584+
.. code-block:: bash
1585+
1586+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
1587+
export SERVER_URL=https://demo.dataverse.org
1588+
export ID=1
1589+
1590+
curl -H "X-Dataverse-key:$API_TOKEN" -X GET "$SERVER_URL/api/dataverses/{ID}/template"
1591+
1592+
The fully expanded example above (without environment variables) looks like this:
1593+
1594+
.. code-block:: bash
1595+
1596+
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X GET "https://demo.dataverse.org/api/dataverses/1/template"
1597+
1598+
You must have Create Dataset permission within the given dataverse collection to invoke this api.
1599+
1600+
Delete a Template by its Identifier
1601+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1602+
1603+
Deletes a template by its ``id``:
1604+
1605+
.. code-block:: bash
1606+
1607+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
1608+
export SERVER_URL=https://demo.dataverse.org
1609+
export ID=1
1610+
1611+
curl -H "X-Dataverse-key:$API_TOKEN" -X DELETE "$SERVER_URL/api/dataverses/{ID}/template"
1612+
1613+
The fully expanded example above (without environment variables) looks like this:
1614+
1615+
.. code-block:: bash
1616+
1617+
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X DELETE "https://demo.dataverse.org/api/dataverses/1/template"
1618+
1619+
You must have Edit Dataverse permission within the given dataverse collection to invoke this api.
1620+
15791621
Create a Template for a Collection
15801622
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15811623

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.collect.Lists;
44
import com.google.api.client.util.ArrayMap;
55
import edu.harvard.iq.dataverse.*;
6+
import static edu.harvard.iq.dataverse.api.AbstractApiBean.error;
67
import edu.harvard.iq.dataverse.api.auth.AuthRequired;
78
import edu.harvard.iq.dataverse.api.datadeposit.SwordServiceBean;
89
import edu.harvard.iq.dataverse.api.dto.*;
@@ -23,6 +24,7 @@
2324
import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItem;
2425
import edu.harvard.iq.dataverse.dataverse.featured.DataverseFeaturedItemServiceBean;
2526
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
27+
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
2628
import edu.harvard.iq.dataverse.engine.command.impl.*;
2729
import edu.harvard.iq.dataverse.pidproviders.PidProvider;
2830
import edu.harvard.iq.dataverse.pidproviders.PidUtil;
@@ -118,6 +120,9 @@ public class Dataverses extends AbstractApiBean {
118120

119121
@EJB
120122
PermissionServiceBean permissionService;
123+
124+
@EJB
125+
TemplateServiceBean templateService;
121126

122127
@EJB
123128
DataverseFeaturedItemServiceBean dataverseFeaturedItemServiceBean;
@@ -1989,6 +1994,21 @@ public Response getTemplates(@Context ContainerRequestContext crc, @PathParam("i
19891994
return e.getResponse();
19901995
}
19911996
}
1997+
1998+
@GET
1999+
@AuthRequired
2000+
@Path("{id}/template/")
2001+
public Response getTemplate(@Context ContainerRequestContext crc, @PathParam("id") Long templateId) {
2002+
try {
2003+
Template template = templateService.find(templateId);
2004+
if (template == null){
2005+
return error(Response.Status.NOT_FOUND, "Template with id " + templateId + " - not found.");
2006+
}
2007+
return ok(jsonTemplate(execCommand(new GetTemplateCommand(createDataverseRequest(getRequestUser(crc)), template))));
2008+
} catch (WrappedResponse e) {
2009+
return e.getResponse();
2010+
}
2011+
}
19922012

19932013
@POST
19942014
@AuthRequired
@@ -2002,7 +2022,10 @@ public Response createTemplate(@Context ContainerRequestContext crc, String body
20022022
} catch (JsonParseException ex) {
20032023
return error(Status.BAD_REQUEST, MessageFormat.format(BundleUtil.getStringFromBundle("dataverse.createTemplate.error.jsonParseMetadataFields"), ex.getMessage()));
20042024
}
2005-
return ok(jsonTemplate(execCommand(new CreateTemplateCommand(newTemplateDTO.toTemplate(), createDataverseRequest(getRequestUser(crc)), dataverse, true))));
2025+
Template created = execCommand(new CreateTemplateCommand(newTemplateDTO.toTemplate(), createDataverseRequest(getRequestUser(crc)), dataverse, true));
2026+
2027+
return created("/dataverses/template/" + created.getId(), jsonTemplate(created));
2028+
20062029
} catch (WrappedResponse e) {
20072030
return e.getResponse();
20082031
}
@@ -2036,6 +2059,27 @@ public Response setMetadataLanguage(@Context ContainerRequestContext crc, @PathP
20362059
}, getRequestUser(crc));
20372060
}
20382061

2062+
@Path("{id}/template")
2063+
@AuthRequired
2064+
@DELETE
2065+
public Response deleteTemplate(@Context ContainerRequestContext crc, @PathParam("id") long id) {
2066+
2067+
Template doomed = templateService.find(id);
2068+
if (doomed == null) {
2069+
return error(Response.Status.NOT_FOUND, "Template with id " + id + " - not found.");
2070+
}
2071+
2072+
Dataverse dv = doomed.getDataverse();
2073+
List<Dataverse> dataverseWDefaultTemplate = templateService.findDataversesByDefaultTemplateId(doomed.getId());
2074+
try {
2075+
execCommand(new DeleteTemplateCommand(createDataverseRequest(getRequestUser(crc)), dv, doomed, dataverseWDefaultTemplate));
2076+
} catch (WrappedResponse wr) {
2077+
return handleWrappedResponse(wr);
2078+
}
2079+
2080+
return ok("Template " + doomed.getName() + " deleted.");
2081+
}
2082+
20392083
@GET
20402084
@AuthRequired
20412085
@Path("{identifier}/assignments/history")

src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateTemplateCommand.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,15 @@ public Template execute(CommandContext ctxt) throws CommandException {
4949
}
5050

5151
Template createdTemplate = ctxt.templates().save(template);
52-
5352
createdTemplate.setIsDefaultForDataverse(template.isIsDefaultForDataverse());
5453
if (initialize && createdTemplate.isIsDefaultForDataverse()) {
5554
dataverse.setDefaultTemplate(createdTemplate);
5655
ctxt.em().merge(dataverse);
57-
}
56+
}
5857

58+
//Flush so that api response can include the id
5959
ctxt.em().flush();
6060
return createdTemplate;
61-
6261
}
6362

6463
private static void updateTermsOfUseAndAccess(CommandContext ctxt, Template template) {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
package edu.harvard.iq.dataverse.engine.command.impl;
3+
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.exception.CommandException;
10+
import java.util.Collections;
11+
import java.util.HashSet;
12+
import java.util.Map;
13+
import java.util.Set;
14+
15+
/**
16+
*
17+
* @author stephenkraffmiller
18+
*/
19+
public class GetTemplateCommand extends AbstractCommand<Template> {
20+
21+
private final Template template;
22+
23+
public GetTemplateCommand (DataverseRequest aRequest, Template template){
24+
super(aRequest, template.getDataverse());
25+
this.template = template;
26+
}
27+
28+
29+
30+
@Override
31+
public Template execute(CommandContext ctxt) throws CommandException {
32+
return template;
33+
}
34+
35+
@Override
36+
public Map<String, Set<Permission>> getRequiredPermissions() {
37+
//at least need add dataset if not published also - view unpublished
38+
Set<Permission> requiredPermissions = new HashSet<>();
39+
40+
requiredPermissions.add(Permission.AddDataset);
41+
if (!template.getDataverse().isReleased()) {
42+
requiredPermissions.add(Permission.ViewUnpublishedDataverse);
43+
}
44+
45+
return Collections.singletonMap("", requiredPermissions);
46+
47+
}
48+
49+
50+
}

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

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2609,6 +2609,10 @@ public void testUpdateInputLevelDisplayOnCreateOverride() {
26092609

26102610
@Test
26112611
public void testCreateAndGetTemplates() throws JsonParseException {
2612+
/*
2613+
Also Delete...and get single template
2614+
*/
2615+
26122616
Response createUserResponse = UtilIT.createRandomUser();
26132617
String apiToken = UtilIT.getApiTokenFromResponse(createUserResponse);
26142618
String username = UtilIT.getUsernameFromResponse(createUserResponse);
@@ -2623,9 +2627,13 @@ public void testCreateAndGetTemplates() throws JsonParseException {
26232627
*/
26242628

26252629
Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
2630+
createDataverseResponse.prettyPrint();
26262631
createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode());
26272632
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
2628-
2633+
Integer dataverseId = UtilIT.getDataverseIdFromResponse(createDataverseResponse);
2634+
2635+
System.out.print("dataverseId: " + dataverseId);
2636+
26292637
String newName = "New Test Dataverse Name";
26302638
String newAffiliation = "New Test Dataverse Affiliation";
26312639
String newDataverseType = Dataverse.DataverseType.TEACHING_COURSES.toString();
@@ -2644,6 +2652,10 @@ public void testCreateAndGetTemplates() throws JsonParseException {
26442652
updateDataverseResponse.then().assertThat()
26452653
.statusCode(OK.getStatusCode());
26462654

2655+
Response publishDataverse = UtilIT.publishDataverseViaNativeApi(dataverseAlias, apiToken);
2656+
assertEquals(200, publishDataverse.getStatusCode());
2657+
assertTrue(publishDataverse.prettyPrint().contains("isReleased\": true"));
2658+
26472659
// Create a template
26482660

26492661
String jsonString = """
@@ -2681,8 +2693,11 @@ public void testCreateAndGetTemplates() throws JsonParseException {
26812693
jsonString,
26822694
apiToken
26832695
);
2696+
2697+
createTemplateResponse.prettyPrint();
2698+
Long templateId = UtilIT.getTemplateIdFromResponse(createTemplateResponse);
26842699

2685-
createTemplateResponse.then().assertThat().statusCode(OK.getStatusCode())
2700+
createTemplateResponse.then().assertThat().statusCode(CREATED.getStatusCode())
26862701
.body("data.name", equalTo("Dataverse template"))
26872702
.body("data.isDefault", equalTo(true))
26882703
.body("data.usageCount", equalTo(0))
@@ -2724,12 +2739,59 @@ public void testCreateAndGetTemplates() throws JsonParseException {
27242739

27252740
// Templates retrieval should succeed if the secondary user has dataset creation permissions
27262741

2742+
2743+
//set to super to update role
27272744
UtilIT.setSuperuserStatus(username, true);
2745+
27282746
Response grantRoleResponse = UtilIT.grantRoleOnDataverse(dataverseAlias, DataverseRole.DS_CONTRIBUTOR, "@" + secondUsername, apiToken);
2747+
grantRoleResponse.prettyPrint();
27292748
grantRoleResponse.then().assertThat().statusCode(OK.getStatusCode());
27302749

27312750
getTemplateResponse = UtilIT.getTemplates(dataverseAlias, secondApiToken);
27322751
getTemplateResponse.then().assertThat().statusCode(OK.getStatusCode());
2752+
2753+
Response getTemplateByIdResponse = UtilIT.getTemplate(templateId.toString(), apiToken);
2754+
getTemplateByIdResponse.prettyPrint();
2755+
getTemplateByIdResponse.then().assertThat().statusCode(OK.getStatusCode());
2756+
2757+
//guest user shouldn't get it
2758+
getTemplateByIdResponse = UtilIT.getTemplate(templateId.toString());
2759+
getTemplateByIdResponse.prettyPrint();
2760+
getTemplateByIdResponse.then().assertThat().statusCode(UNAUTHORIZED.getStatusCode());
2761+
2762+
Response deleteTemplateResponse = UtilIT.deleteTemplate(templateId.toString(), secondApiToken);
2763+
deleteTemplateResponse.prettyPrint();
2764+
deleteTemplateResponse.then().assertThat().statusCode(UNAUTHORIZED.getStatusCode());
2765+
2766+
//set back to show super not needed for delete - just Edit Dataverse
2767+
UtilIT.setSuperuserStatus(username, false);
2768+
2769+
String badId = "8675309";
2770+
2771+
deleteTemplateResponse = UtilIT.deleteTemplate(badId, apiToken);
2772+
deleteTemplateResponse.prettyPrint();
2773+
deleteTemplateResponse.then().assertThat().statusCode(NOT_FOUND.getStatusCode());
2774+
2775+
deleteTemplateResponse = UtilIT.deleteTemplate(templateId.toString(), apiToken);
2776+
deleteTemplateResponse.prettyPrint();
2777+
deleteTemplateResponse.then().assertThat().statusCode(OK.getStatusCode());
2778+
// back to super for cleanup
2779+
2780+
UtilIT.setSuperuserStatus(username, true);
2781+
2782+
Response deleteDataverse1Response = UtilIT.deleteDataverse(dataverseAlias, apiToken);
2783+
deleteDataverse1Response.prettyPrint();
2784+
assertEquals(200, deleteDataverse1Response.getStatusCode());
2785+
2786+
Response deleteUserResponse = UtilIT.deleteUser(secondUsername);
2787+
deleteUserResponse.prettyPrint();
2788+
assertEquals(200, deleteUserResponse.getStatusCode());
2789+
2790+
deleteUserResponse = UtilIT.deleteUser(username);
2791+
deleteUserResponse.prettyPrint();
2792+
assertEquals(200, deleteUserResponse.getStatusCode());
2793+
2794+
27332795
}
27342796

27352797
@Test

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,13 @@ static Integer getDataverseIdFromResponse(Response createDataverseResponse) {
337337
logger.info("Id found in create dataverse response: " + dataverseId);
338338
return dataverseId;
339339
}
340+
341+
static Long getTemplateIdFromResponse(Response createTemplateResponse) {
342+
JsonPath createdTemplate = JsonPath.from(createTemplateResponse.body().asString());
343+
Long templateId = createdTemplate.getLong("data.id");
344+
logger.info("Id found in create template response: " + templateId);
345+
return templateId;
346+
}
340347

341348
static Integer getDatasetIdFromResponse(Response createDatasetResponse) {
342349
JsonPath createdDataset = JsonPath.from(createDatasetResponse.body().asString());
@@ -5137,6 +5144,12 @@ public static Response createTemplate(String dataverseAlias, String jsonString,
51375144
.body(jsonString)
51385145
.post("/api/dataverses/" + dataverseAlias + "/templates");
51395146
}
5147+
5148+
public static Response deleteTemplate(String id, String apiToken) {
5149+
return given()
5150+
.header(API_TOKEN_HTTP_HEADER, apiToken)
5151+
.delete("/api/dataverses/"+id+"/template");
5152+
}
51405153

51415154
public static Response getTemplates(String dataverseAlias, String apiToken) {
51425155
return given()
@@ -5145,6 +5158,19 @@ public static Response getTemplates(String dataverseAlias, String apiToken) {
51455158
.get("/api/dataverses/" + dataverseAlias + "/templates");
51465159
}
51475160

5161+
public static Response getTemplate(String templateId) {
5162+
return given()
5163+
.contentType(ContentType.JSON)
5164+
.get("/api/dataverses/" + templateId + "/template");
5165+
}
5166+
5167+
public static Response getTemplate(String templateId, String apiToken) {
5168+
return given()
5169+
.contentType(ContentType.JSON)
5170+
.header(API_TOKEN_HTTP_HEADER, apiToken)
5171+
.get("/api/dataverses/" + templateId + "/template");
5172+
}
5173+
51485174
/**
51495175
* Gets the tool URL for a dataset with optional parameters
51505176
* @param datasetId The ID of the dataset

0 commit comments

Comments
 (0)