Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Publishing Enhancement ##

Before a Dataset can be published the user must acknowledge acceptance of the legal disclaimer if it is required.

The setting "DatasetPublishLegalDisclaimerAcknowledgementRequired", when set to `true`, will prevent a draft dataset from being published without the user acknowledging the legal disclaimer.

APIs: If the setting is set to true and the dataset version is in draft the GET Dataset and GET Dataset Version APIs will include the legal disclaimer text in the Json response. The publish Dataset API will require a query parameter `legalDisclaimerAcknowledged=true` to publish this Dataset.

The UI will prevent the user from publishing a Dataset unless the legal disclaimer is acknowledged.

9 changes: 9 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/DatasetPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -6251,6 +6251,7 @@ public void setFileMetadataForAction(FileMetadata fileMetadataForAction) {

private String termsOfAccess;
private boolean fileAccessRequest;
private boolean legalDisclaimerAcknowledged;

public String getTermsOfAccess() {
return termsOfAccess;
Expand All @@ -6268,6 +6269,14 @@ public void setFileAccessRequest(boolean fileAccessRequest) {
this.fileAccessRequest = fileAccessRequest;
}

public boolean isLegalDisclaimerAcknowledged() {
return legalDisclaimerAcknowledged;
}

public void setLegalDisclaimerAcknowledged(boolean legalDisclaimerAcknowledged) {
this.legalDisclaimerAcknowledged = legalDisclaimerAcknowledged;
}

// wrapper method to see if the file has been deleted (or replaced) in the current version
public boolean isFileDeleted (DataFile dataFile) {
if (dataFile.getDeleted() == null) {
Expand Down
24 changes: 18 additions & 6 deletions src/main/java/edu/harvard/iq/dataverse/api/Datasets.java
Original file line number Diff line number Diff line change
Expand Up @@ -1196,13 +1196,16 @@ public Response editVersionTermsOfAccess(@Context ContainerRequestContext crc, S
@Deprecated
public Response publishDataseUsingGetDeprecated(@Context ContainerRequestContext crc, @PathParam("id") String id, @QueryParam("type") String type ) {
logger.info("publishDataseUsingGetDeprecated called on id " + id + ". Encourage use of POST rather than GET, which is deprecated.");
return publishDataset(crc, id, type, false);
return publishDataset(crc, id, type, false, false);
}

@POST
@AuthRequired
@Path("{id}/actions/:publish")
public Response publishDataset(@Context ContainerRequestContext crc, @PathParam("id") String id, @QueryParam("type") String type, @QueryParam("assureIsIndexed") boolean mustBeIndexed) {
public Response publishDataset(@Context ContainerRequestContext crc, @PathParam("id") String id,
@QueryParam("type") String type,
@QueryParam("assureIsIndexed") boolean mustBeIndexed,
@QueryParam("legalDisclaimerAcknowledged") boolean legalDisclaimerAcknowledged) {
try {
if (type == null) {
return error(Response.Status.BAD_REQUEST, "Missing 'type' parameter (either 'major','minor', or 'updatecurrent').");
Expand Down Expand Up @@ -1316,15 +1319,24 @@ public Response publishDataset(@Context ContainerRequestContext crc, @PathParam(
.build();
}
} else {
PublishDatasetResult res = execCommand(new PublishDatasetCommand(ds,
createDataverseRequest(user),
isMinor));
return res.isWorkflow() ? accepted(json(res.getDataset())) : ok(json(res.getDataset()));
if (isLegalDisclaimerAcknowledged(user, legalDisclaimerAcknowledged)) {
PublishDatasetResult res = execCommand(new PublishDatasetCommand(ds,
createDataverseRequest(user),
isMinor));
return res.isWorkflow() ? accepted(json(res.getDataset())) : ok(json(res.getDataset()));
} else {
return error(Status.PRECONDITION_FAILED, "Legal Disclaimer not Acknowledged"); // 412
}
}
} catch (WrappedResponse ex) {
return ex.getResponse();
}
}
private boolean isLegalDisclaimerAcknowledged(AuthenticatedUser user, boolean legalDisclaimerAcknowledged) {
return (user.isSuperuser()
|| !("true".equalsIgnoreCase(settingsService.getValueForKey(SettingsServiceBean.Key.DatasetPublishLegalDisclaimerAcknowledgementRequired)))
|| legalDisclaimerAcknowledged);
}

@POST
@AuthRequired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ <p>Size limit (in bytes) for tabular file ingest. Accepts either a single numeri
*/
DatasetPublishPopupCustomTextOnAllVersions,
/*
Whether a Legal Disclaimer must be acknowledged before a Dataset can be published
*/
DatasetPublishLegalDisclaimerAcknowledgementRequired,
/*
Whether Harvesting (OAI) service is enabled
*/
OAIServerEnabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ public static JsonObjectBuilder json(Dataset ds, Boolean returnOwners) {
.add("publicationDate", ds.getPublicationDateFormattedYYYYMMDD())
.add("storageIdentifier", ds.getStorageIdentifier());
addDatasetFileCountLimit(ds, bld);
includePublishLegalDisclaimer(bld, ds.getLatestVersion());

if (DvObjectContainer.isMetadataLanguageSet(ds.getMetadataLanguage())) {
bld.add("metadataLanguage", ds.getMetadataLanguage());
Expand Down Expand Up @@ -571,6 +572,7 @@ public static JsonObjectBuilder json(DatasetVersion dsv, List<String> anonymized
.add("sizeOfCollection", dsv.getTermsOfUseAndAccess().getSizeOfCollection())
.add("studyCompletion", dsv.getTermsOfUseAndAccess().getStudyCompletion())
.add("fileAccessRequest", dsv.getTermsOfUseAndAccess().isFileAccessRequest());
includePublishLegalDisclaimer(bld, dsv);
if(includeMetadataBlocks) {
bld.add("metadataBlocks",
jsonByBlocks(dsv.getDatasetFields(), anonymizedFieldTypeNamesList, ignoreSettingExcludeEmailFromExport));
Expand Down Expand Up @@ -1784,4 +1786,10 @@ public static JsonArrayBuilder jsonFileVersionSummaries(List<FileVersionDifferen

return arrayBuilder;
}

private static void includePublishLegalDisclaimer(JsonObjectBuilder jsonbuilder, DatasetVersion dsv) {
if (dsv != null && dsv.isDraft() && settingsService.isTrueForKey(SettingsServiceBean.Key.DatasetPublishLegalDisclaimerAcknowledgementRequired, false)) {
jsonbuilder.add("publishLegalDisclaimer", BundleUtil.getStringFromBundle("dataset.publish.legal.disclaimer"));
}
}
}
1 change: 1 addition & 0 deletions src/main/java/propertyFiles/Bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,7 @@ dataset.reject.failure=Dataset Submission Return Failed - {0}
dataset.reject.datasetNull=Cannot return the dataset to the author(s) because it is null.
dataset.reject.datasetNotInReview=This dataset cannot be return to the author(s) because the latest version is not In Review. The author(s) needs to click Submit for Review first.
dataset.reject.commentNull=You must enter a reason for returning a dataset to the author(s).
dataset.publish.legal.disclaimer=By publishing this dataset, I fully accept all legal responsibility for ensuring that the deposited content is: anonymized, free of copyright violations, and contains data that is computationally reusable. I understand and agree that any violation of these conditions may result in the immediate removal of the dataset by the repository without prior notice.
dataset.publish.tip=Are you sure you want to publish this dataset? Once you do so it must remain published.
dataset.publish.terms.tip=This version of the dataset will be published with the following terms:
dataset.publish.terms.help.tip=To change the terms for this version, click the Cancel button and go to the Terms tab for this dataset.
Expand Down
18 changes: 14 additions & 4 deletions src/main/webapp/dataset.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -2029,8 +2029,18 @@
<p class="col-sm-12 help-block">#{bundle['dataset.publish.terms.help.tip']}</p>
</div>
</ui:fragment>
<ui:fragment rendered="#{valid}">
<div class="form-group">
<p:selectBooleanCheckbox class="text-danger" id="legalDisclaimer"
itemLabel="#{bundle['dataset.publish.legal.disclaimer']}"
value="#{DatasetPage.legalDisclaimerAcknowledged}">
<p:ajax event="change" update="releaseDatasetButton"/>
</p:selectBooleanCheckbox>
</div>
</ui:fragment>
<div class="button-block">
<p:commandButton rendered="#{valid}" styleClass="btn btn-default" value="#{bundle.continue}"
<p:commandButton id="releaseDatasetButton" rendered="#{valid}" styleClass="btn btn-default" value="#{bundle.continue}"
disabled="#{!DatasetPage.legalDisclaimerAcknowledged}"
onclick="PF('publishDataset').hide();
PF('blockDatasetForm').hide();" action="#{DatasetPage.releaseDataset}" />
<button class="btn btn-link" onclick="PF('publishDataset').hide();
Expand Down Expand Up @@ -2085,7 +2095,7 @@
<p class="text-warning">
<span class="glyphicon glyphicon-warning-sign"/> #{bundle['dataset.rejectMessage']} #{disableReasonField ? '':bundle['dataset.rejectMessageReason']}
</p>

<ui:fragment rendered="#{!disableReasonField}">
<p:inputTextarea id="returnReason" rows="4" value="#{DatasetPage.returnReason}" title="#{bundle['dataset.rejectMessage.label']}" maxlength="2000" widgetVar="returnReason"
cols="70" counter="display" counterTemplate="{0} characters remaining." autoResize="false"
Expand All @@ -2097,7 +2107,7 @@
<p:watermark for="returnReason" value="#{bundle['dataset.rejectWatermark']}" id="returnReasonWatermark"/>
<h:message for="returnReason" styleClass="bg-danger text-danger"/>
</ui:fragment>

<div class="button-block">
<p:commandButton styleClass="btn btn-default" value="#{bundle.continue}"
update="@form"
Expand Down Expand Up @@ -2182,7 +2192,7 @@
<script>
Cite.CSL.register.addTemplate("#{requestedCSL}",
"#{CSLUtil:getCitationFormat((requestedCSL == '') ? 'apa' : requestedCSL)}");

document.getElementById('datasetForm:cslOutput').innerHTML = cite.format("bibliography", {
format: "html",
template: "#{requestedCSL}",
Expand Down
63 changes: 63 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public static void afterClass() {
.statusCode(200);

UtilIT.deleteSetting(SettingsServiceBean.Key.MaxEmbargoDurationInMonths);
UtilIT.deleteSetting(SettingsServiceBean.Key.DatasetPublishLegalDisclaimerAcknowledgementRequired);

/* See above
Response removeDcmUrl = UtilIT.deleteSetting(SettingsServiceBean.Key.DataCaptureModuleUrl);
Expand Down Expand Up @@ -7413,6 +7414,68 @@ public void testExcludeEmailOverride() {
assertTrue(!json.contains("datasetContactEmail"));
}

@Test
public void testDatasetPublishLegalDisclaimerAcknowledgementRequired() {
// Test setup: Create a user and a published dataverse to host the datasets.
Response createUser = UtilIT.createRandomUser();
String apiToken = UtilIT.getApiTokenFromResponse(createUser);
String adminApiToken = getSuperuserToken();
Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
String ownerAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
UtilIT.publishDataverseViaNativeApi(ownerAlias, apiToken);

// Test setup: Create datasets within the new dataverse.
Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(ownerAlias, apiToken);
String datasetPersistentId1 = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse);
createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(ownerAlias, apiToken);
String datasetPersistentId2 = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse);
createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(ownerAlias, apiToken);
String datasetPersistentId3 = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse);
createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(ownerAlias, apiToken);
String datasetPersistentId4 = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse);

// Require the acknowledgement
UtilIT.setSetting(SettingsServiceBean.Key.DatasetPublishLegalDisclaimerAcknowledgementRequired, "true");
// Acknowledgement required means Draft datasets include publishLegalDisclaimer in Json GET response
Response getResp = UtilIT.nativeGetUsingPersistentId(datasetPersistentId1, apiToken);
getResp.then().assertThat().statusCode(OK.getStatusCode());
String json = getResp.prettyPrint();
assertTrue(json.contains("publishLegalDisclaimer"));
getResp = UtilIT.getDatasetVersion(datasetPersistentId1, ":draft", apiToken);
getResp.then().assertThat().statusCode(OK.getStatusCode());
json = getResp.prettyPrint();
assertTrue(json.contains("publishLegalDisclaimer"));

Response publishDataset1 = UtilIT.publishDatasetViaNativeApi(datasetPersistentId1, "major", apiToken);
Response publishDataset2 = UtilIT.publishDatasetViaNativeApi(datasetPersistentId2, "major", apiToken, false, "&legalDisclaimerAcknowledged=true");
Response publishDataset3 = UtilIT.publishDatasetViaNativeApi(datasetPersistentId3, "major", adminApiToken);

// Acknowledgement not required
UtilIT.setSetting(SettingsServiceBean.Key.DatasetPublishLegalDisclaimerAcknowledgementRequired, "false");
Response publishDataset4 = UtilIT.publishDatasetViaNativeApi(datasetPersistentId4, "major", apiToken, false, "&legalDisclaimerAcknowledged=false");
// No Acknowledgement means no publishLegalDisclaimer in Json GET response
getResp = UtilIT.nativeGetUsingPersistentId(datasetPersistentId1, apiToken);
getResp.then().assertThat().statusCode(OK.getStatusCode());
json = getResp.prettyPrint();
assertTrue(!json.contains("publishLegalDisclaimer"));

// verify that the first publish failed since the acknowledgement was missing
publishDataset1.then().assertThat()
.statusCode(PRECONDITION_FAILED.getStatusCode())
.body("message", equalTo("Legal Disclaimer not Acknowledged"));
// verify that the second publish passed since the acknowledgement was true
publishDataset2.then().assertThat()
.statusCode(OK.getStatusCode());
// verify that the third publish passed without acknowledgement since the user was a superuser
publishDataset3.then().assertThat()
.statusCode(OK.getStatusCode());
// verify that the forth publish passes with legalDisclaimerAcknowledged=false since the acknowledgement isn't required
publishDataset4.then().assertThat()
.statusCode(OK.getStatusCode());

UtilIT.deleteSetting(SettingsServiceBean.Key.DatasetPublishLegalDisclaimerAcknowledgementRequired);
}

private String getSuperuserToken() {
Response createResponse = UtilIT.createRandomUser();
String adminApiToken = UtilIT.getApiTokenFromResponse(createResponse);
Expand Down
8 changes: 7 additions & 1 deletion src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -1614,8 +1614,11 @@ static Response publishDatasetViaSword(String persistentId, String apiToken) {
static Response publishDatasetViaNativeApi(String idOrPersistentId, String majorOrMinor, String apiToken) {
return publishDatasetViaNativeApi(idOrPersistentId, majorOrMinor, apiToken, false);
}

static Response publishDatasetViaNativeApi(String idOrPersistentId, String majorOrMinor, String apiToken, boolean mustBeIndexed) {
return publishDatasetViaNativeApi(idOrPersistentId, majorOrMinor, apiToken, mustBeIndexed, null);
}

static Response publishDatasetViaNativeApi(String idOrPersistentId, String majorOrMinor, String apiToken, boolean mustBeIndexed, String params) {

String idInPath = idOrPersistentId; // Assume it's a number.
String optionalQueryParam = ""; // If idOrPersistentId is a number we'll just put it in the path.
Expand All @@ -1626,6 +1629,9 @@ static Response publishDatasetViaNativeApi(String idOrPersistentId, String major
if(mustBeIndexed) {
optionalQueryParam = optionalQueryParam+"&assureIsIndexed=true";
}
if (params != null) {
optionalQueryParam = optionalQueryParam+params;
}
RequestSpecification requestSpecification = given();
if (apiToken != null) {
requestSpecification = given()
Expand Down