Skip to content

Commit 14705ce

Browse files
authored
Merge pull request #11893 from IQSS/11772-api-terms-of-access
11772 api terms of access
2 parents a8fac19 + f648084 commit 14705ce

File tree

13 files changed

+520
-6
lines changed

13 files changed

+520
-6
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## New Endpoint: `/datasets/{id}/access`
2+
3+
A new endpoint has been implemented to manage dataset terms of access for restricted files.
4+
5+
### Functionality
6+
- Updates the terms of access for a dataset by applying it to the draft version.
7+
- If no draft exists, a new one is automatically created.
8+
9+
### Usage
10+
11+
**Custom Terms of Access** – Provide a JSON body with the `customTermsOfAccess` object.
12+
- All fields are optional **except** if there are restricted files in which case `fileAccessRequest` must be set to true or `termsOfAccess` must be provided.

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2298,6 +2298,46 @@ For these deletes your JSON file must include an exact match of those dataset fi
22982298

22992299
.. _publish-dataset-api:
23002300

2301+
Update Dataset Terms of Access
2302+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2303+
2304+
Updates the terms of access for the restricted files of a dataset by applying it to the draft version, or by creating a draft if none exists.
2305+
2306+
2307+
To define custom terms of access, provide a JSON body with the following properties. All fields within ``customTermsOfAccess`` are optional, except if there are restricted files in your dataset then ``fileAccessRequest`` must be set to true or ``termsOfAccess`` must be provided:
2308+
2309+
.. code-block:: json
2310+
2311+
[
2312+
{
2313+
"customTermsOfAccess": {
2314+
"fileAccessRequest": true,
2315+
"termsOfAccess": "Your terms of access for restricted files",
2316+
"dataAccessPlace": "Your data access place",
2317+
"originalArchive": "Your original archive",
2318+
"availabilityStatus": "Your availability status",
2319+
"contactForAccess": "Your contact for access",
2320+
"sizeOfCollection": "Your size of collection",
2321+
"studyCompletion": "Your study completion"
2322+
}
2323+
}
2324+
]
2325+
2326+
.. code-block:: bash
2327+
2328+
export API_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
2329+
export SERVER_URL=https://demo.dataverse.org
2330+
export ID=3
2331+
export FILE_PATH=access.json
2332+
2333+
curl -H "X-Dataverse-key:$API_TOKEN" -X PUT "$SERVER_URL/api/datasets/$ID/access" -H "Content-type:application/json" --upload-file $FILE_PATH
2334+
2335+
The fully expanded example above (without environment variables) looks like this:
2336+
2337+
.. code-block:: bash
2338+
2339+
curl -H "X-Dataverse-key:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -X PUT "https://demo.dataverse.org/api/datasets/3/access" -H "Content-type:application/json" --upload-file access.json
2340+
23012341
Publish a Dataset
23022342
~~~~~~~~~~~~~~~~~
23032343

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,42 @@ public Response editVersionMetadata(@Context ContainerRequestContext crc, String
11521152
return ex.getResponse();
11531153
}
11541154
}
1155+
1156+
@PUT
1157+
@AuthRequired
1158+
@Path("{id}/access")
1159+
public Response editVersionTermsOfAccess(@Context ContainerRequestContext crc, String jsonBody, @PathParam("id") String id,
1160+
@QueryParam("sourceLastUpdateTime") String sourceLastUpdateTime) {
1161+
try {
1162+
1163+
boolean publicInstall = settingsSvc.isTrueForKey(SettingsServiceBean.Key.PublicInstall, false);
1164+
1165+
Dataset dataset = findDatasetOrDie(id);
1166+
1167+
if (sourceLastUpdateTime != null) {
1168+
validateInternalTimestampIsNotOutdated(dataset, sourceLastUpdateTime);
1169+
}
1170+
1171+
JsonObject json = JsonUtil.getJsonObject(jsonBody);
1172+
1173+
TermsOfUseAndAccess toua = jsonParser().parseTermsOfAccess(json);
1174+
1175+
if (publicInstall && (toua.isFileAccessRequest() || !toua.getTermsOfAccess().isEmpty())){
1176+
return error(BAD_REQUEST, "Setting File Access Request or Terms of Access is not permitted on a public installation.");
1177+
}
1178+
1179+
DatasetVersion updatedVersion = execCommand(new UpdateDatasetTermsOfAccessCommand(dataset, toua, createDataverseRequest(getRequestUser(crc)))).getLatestVersion();
1180+
1181+
return ok(json(updatedVersion, true));
1182+
1183+
} catch (JsonParseException ex) {
1184+
logger.log(Level.SEVERE, "Semantic error parsing dataset terms update Json: " + ex.getMessage(), ex);
1185+
return error(Response.Status.BAD_REQUEST, BundleUtil.getStringFromBundle("datasets.api.editMetadata.error.parseUpdate", List.of(ex.getMessage())));
1186+
} catch (WrappedResponse ex) {
1187+
logger.log(Level.SEVERE, "Update terms of use error: " + ex.getMessage(), ex);
1188+
return ex.getResponse();
1189+
}
1190+
}
11551191

11561192
/**
11571193
* @deprecated This was shipped as a GET but should have been a POST, see https://github.com/IQSS/dataverse/issues/2431
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
package edu.harvard.iq.dataverse.engine.command.impl;
3+
4+
import edu.harvard.iq.dataverse.Dataset;
5+
import edu.harvard.iq.dataverse.DatasetVersion;
6+
import edu.harvard.iq.dataverse.TermsOfUseAndAccess;
7+
import edu.harvard.iq.dataverse.authorization.Permission;
8+
import edu.harvard.iq.dataverse.engine.command.CommandContext;
9+
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
10+
import edu.harvard.iq.dataverse.engine.command.RequiredPermissions;
11+
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
12+
13+
14+
/**
15+
*
16+
* @author stephenkraffmiller
17+
*/
18+
@RequiredPermissions(Permission.EditDataset)
19+
public class UpdateDatasetTermsOfAccessCommand extends AbstractDatasetCommand<Dataset>{
20+
21+
22+
private final Dataset dataset;
23+
private final TermsOfUseAndAccess termsOfUseAndAccess;
24+
private final UpdateDatasetVersionCommand updateDatasetVersionCommand;
25+
26+
public UpdateDatasetTermsOfAccessCommand(Dataset dataset, TermsOfUseAndAccess termsOfUseAndAccess, DataverseRequest request) {
27+
this(dataset, termsOfUseAndAccess, request, null);
28+
}
29+
30+
//Command included for testing purposes
31+
public UpdateDatasetTermsOfAccessCommand( Dataset dataset, TermsOfUseAndAccess termsOfUseAndAccess, DataverseRequest aRequest, UpdateDatasetVersionCommand updateDatasetVersionCommand ) {
32+
super(aRequest, dataset);
33+
this.dataset = dataset;
34+
this.termsOfUseAndAccess = termsOfUseAndAccess;
35+
this.updateDatasetVersionCommand = updateDatasetVersionCommand;
36+
}
37+
38+
@Override
39+
public Dataset execute(CommandContext ctxt) throws CommandException {
40+
DatasetVersion datasetVersion = dataset.getOrCreateEditVersion();
41+
42+
datasetVersion.setTermsOfUseAndAccess(merge(datasetVersion,termsOfUseAndAccess));
43+
44+
datasetVersion.setVersionState(DatasetVersion.VersionState.DRAFT);
45+
return ctxt.engine().submit(updateDatasetVersionCommand == null ? new UpdateDatasetVersionCommand(this.dataset, getRequest()) : updateDatasetVersionCommand);
46+
}
47+
48+
private TermsOfUseAndAccess merge(DatasetVersion editVersion, TermsOfUseAndAccess incoming) {
49+
//only update the access parts
50+
TermsOfUseAndAccess termsToUpdate = editVersion.getTermsOfUseAndAccess();
51+
termsToUpdate.setFileAccessRequest(incoming.isFileAccessRequest());
52+
termsToUpdate.setTermsOfAccess(incoming.getTermsOfAccess());
53+
termsToUpdate.setDataAccessPlace(incoming.getDataAccessPlace());
54+
termsToUpdate.setOriginalArchive(incoming.getOriginalArchive());
55+
termsToUpdate.setAvailabilityStatus(incoming.getAvailabilityStatus());
56+
termsToUpdate.setContactForAccess(incoming.getContactForAccess());
57+
termsToUpdate.setSizeOfCollection(incoming.getSizeOfCollection());
58+
termsToUpdate.setStudyCompletion(incoming.getStudyCompletion());
59+
return termsToUpdate;
60+
}
61+
62+
63+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public Dataset execute(CommandContext ctxt) throws CommandException {
100100
if ( ! (getUser() instanceof AuthenticatedUser) ) {
101101
throw new IllegalCommandException("Only authenticated users can update datasets", this);
102102
}
103-
103+
104104
Dataset theDataset = getDataset();
105105
ctxt.permissions().checkUpdateDatasetVersionLock(theDataset, getRequest(), this);
106106
Dataset savedDataset = null;
@@ -136,6 +136,7 @@ public Dataset execute(CommandContext ctxt) throws CommandException {
136136
}
137137

138138
getDataset().getOrCreateEditVersion(fmVarMet).setDatasetFields(getDataset().getOrCreateEditVersion(fmVarMet).initDatasetFields());
139+
139140
validateOrDie(getDataset().getOrCreateEditVersion(fmVarMet), isValidateLenient());
140141

141142
final DatasetVersion editVersion = getDataset().getOrCreateEditVersion(fmVarMet);

src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,51 @@ public static <E extends Enum<E>> List<E> parseEnumsFromArray(JsonArray enumsArr
377377
}
378378
return enums;
379379
}
380+
381+
public TermsOfUseAndAccess parseTermsOfUseAndAccess(JsonObject obj) throws JsonParseException {
382+
JsonObject terms = obj.getJsonObject("termsOfUseAndAccess");
383+
TermsOfUseAndAccess toaa = new TermsOfUseAndAccess();
384+
toaa.setTermsOfUse(terms.getString("termsOfUse", null));
385+
toaa.setConfidentialityDeclaration(terms.getString("confidentialityDeclaration", null));
386+
toaa.setSpecialPermissions(terms.getString("specialPermissions", null));
387+
toaa.setRestrictions(terms.getString("restrictions", null));
388+
toaa.setCitationRequirements(terms.getString("citationRequirements", null));
389+
toaa.setDepositorRequirements(terms.getString("depositorRequirements", null));
390+
toaa.setConditions(terms.getString("conditions", null));
391+
toaa.setDisclaimer(terms.getString("disclaimer", null));
392+
return parseTermsOfAccess(obj, toaa);
393+
}
394+
395+
public TermsOfUseAndAccess parseTermsOfAccess(JsonObject obj) throws JsonParseException {
396+
return parseTermsOfAccess(obj, null);
397+
}
398+
399+
public TermsOfUseAndAccess parseTermsOfAccess(JsonObject obj, TermsOfUseAndAccess touaIn) throws JsonParseException {
400+
//This only gets values associated with the terms of access for restricted files when no TermsOfUseAndAccess object provided
401+
// or added to an existing object when provided
402+
403+
JsonObject terms;
404+
TermsOfUseAndAccess toaa;
405+
if (touaIn == null) {
406+
terms = obj.getJsonObject("customTermsOfAccess");
407+
toaa = new TermsOfUseAndAccess();
408+
} else {
409+
terms = obj.getJsonObject("termsOfUseAndAccess");
410+
toaa = touaIn;
411+
}
412+
413+
toaa.setFileAccessRequest(terms.getBoolean("fileAccessRequest", false));
414+
toaa.setTermsOfAccess(terms.getString("termsOfAccess", null));
415+
toaa.setDataAccessPlace(terms.getString("dataAccessPlace", null));
416+
toaa.setOriginalArchive(terms.getString("originalArchive", null));
417+
toaa.setAvailabilityStatus(terms.getString("availabilityStatus", null));
418+
toaa.setContactForAccess(terms.getString("contactForAccess", null));
419+
toaa.setSizeOfCollection(terms.getString("sizeOfCollection", null));
420+
toaa.setStudyCompletion(terms.getString("studyCompletion", null));
421+
toaa.setConfidentialityDeclaration(terms.getString("confidentialityDeclaration", null));
422+
423+
return toaa;
424+
}
380425

381426
public DatasetVersion parseDatasetVersion(JsonObject obj) throws JsonParseException {
382427
return parseDatasetVersion(obj, new DatasetVersion());

src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ public static JsonObjectBuilder json(FileDetailsHolder ds) {
512512
}
513513

514514
public static JsonObjectBuilder json(DatasetVersion dsv, boolean includeFiles) {
515-
return json(dsv, null, includeFiles, false,true);
515+
return json(dsv, null, includeFiles, false, true);
516516
}
517517
public static JsonObjectBuilder json(DatasetVersion dsv, boolean includeFiles, boolean includeMetadataBlocks) {
518518
return json(dsv, null, includeFiles, false, includeMetadataBlocks);

0 commit comments

Comments
 (0)