Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prevent double linking of datasets and dataverses #7259 #7415

Merged
merged 6 commits into from
Nov 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion conf/docker-aio/run-test-suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ fi

# Please note the "dataverse.test.baseurl" is set to run for "all-in-one" Docker environment.
# TODO: Rather than hard-coding the list of "IT" classes here, add a profile to pom.xml.
mvn test -Dtest=DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT,AccessIT,DuplicateFilesIT,DownloadFilesIT -Ddataverse.test.baseurl=$dvurl
mvn test -Dtest=DataversesIT,DatasetsIT,SwordIT,AdminIT,BuiltinUsersIT,UsersIT,UtilIT,ConfirmEmailIT,FileMetadataIT,FilesIT,SearchIT,InReviewWorkflowIT,HarvestingServerIT,MoveIT,MakeDataCountApiIT,FileTypeDetectionIT,EditDDIIT,ExternalToolsIT,AccessIT,DuplicateFilesIT,DownloadFilesIT,LinkIT -Ddataverse.test.baseurl=$dvurl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public DatasetLinkingDataverse execute(CommandContext ctxt) throws CommandExcept
if (linkedDataset.getOwner().getOwners().contains(linkingDataverse)) {
throw new IllegalCommandException(BundleUtil.getStringFromBundle("dataset.link.not.to.parent.dataverse"), this);
}
if (ctxt.dsLinking().alreadyLinked(linkingDataverse, linkedDataset)) {
throw new IllegalCommandException(BundleUtil.getStringFromBundle("dataset.link.not.already.linked"), this);
}

DatasetLinkingDataverse datasetLinkingDataverse = new DatasetLinkingDataverse();
datasetLinkingDataverse.setDataset(linkedDataset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException;
import edu.harvard.iq.dataverse.engine.command.exception.PermissionException;
import edu.harvard.iq.dataverse.util.BundleUtil;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -53,6 +55,9 @@ public DataverseLinkingDataverse execute(CommandContext ctxt) throws CommandExce
if (linkedDataverse.getOwners().contains(linkingDataverse)) {
throw new IllegalCommandException("Can't link a dataverse to its parents", this);
}
if (ctxt.dvLinking().alreadyLinked(linkingDataverse, linkedDataverse)) {
throw new IllegalCommandException(BundleUtil.getStringFromBundle("dataverse.linked.error.alreadyLinked", Arrays.asList(linkedDataverse.getName(), linkingDataverse.getName())), this);
}

DataverseLinkingDataverse dataverseLinkingDataverse = new DataverseLinkingDataverse();
dataverseLinkingDataverse.setDataverse(linkedDataverse);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/propertyFiles/Bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,7 @@ dataverse.saved.search.failure=The saved search was not able to be linked.
dataverse.linked.success= {0} has been successfully linked to {1}.
dataverse.linked.success.wait= {0} has been successfully linked to {1}. Please wait for its contents to appear.
dataverse.linked.internalerror={0} has been successfully linked to {1} but contents will not appear until an internal error has been fixed.
dataverse.linked.error.alreadyLinked={0} has already been linked to {1}.
dataverse.page.pre=Previous
dataverse.page.next=Next
dataverse.byCategory=Dataverses by Category
Expand Down Expand Up @@ -1314,6 +1315,7 @@ dataset.link.not.to.owner=Can't link a dataset to its dataverse
dataset.link.not.to.parent.dataverse=Can't link a dataset to its parent dataverses
dataset.link.not.published=Can't link a dataset that has not been published
dataset.link.not.available=Can't link a dataset that has not been published or is not harvested
dataset.link.not.already.linked=Can't link a dataset that has already been linked to this dataverse
dataset.email.datasetContactTitle=Contact Dataset Owner
dataset.email.hiddenMessage=
dataset.email.messageSubject=Test Message Subject
Expand Down
37 changes: 3 additions & 34 deletions src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -383,40 +383,9 @@ public void testMoveDataverse() {
}

}

@Test
public void testCreateDeleteDataverseLink() {
Response createUser = UtilIT.createRandomUser();

createUser.prettyPrint();
String username = UtilIT.getUsernameFromResponse(createUser);
String apiToken = UtilIT.getApiTokenFromResponse(createUser);

Response superuserResponse = UtilIT.makeSuperUser(username);

Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
createDataverseResponse.prettyPrint();
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
Integer dataverseId = UtilIT.getDataverseIdFromResponse(createDataverseResponse);

Response createDataverseResponse2 = UtilIT.createRandomDataverse(apiToken);
createDataverseResponse2.prettyPrint();
String dataverseAlias2 = UtilIT.getAliasFromResponse(createDataverseResponse2);

Response createLinkingDataverseResponse = UtilIT.createDataverseLink(dataverseAlias, dataverseAlias2, apiToken);
createLinkingDataverseResponse.prettyPrint();

createLinkingDataverseResponse.then().assertThat()
.body("data.message", equalTo("Dataverse " + dataverseAlias + " linked successfully to " + dataverseAlias2))
.statusCode(200);

Response deleteLinkingDataverseResponse = UtilIT.deleteDataverseLink(dataverseAlias, dataverseAlias2, apiToken);
deleteLinkingDataverseResponse.prettyPrint();
deleteLinkingDataverseResponse.then().assertThat()
.body("data.message", equalTo("Link from Dataverse " + dataverseAlias + " to linked Dataverse " + dataverseAlias2 + " deleted"))
.statusCode(200);
}


// testCreateDeleteDataverseLink was here but is now in LinkIT

@Test
public void testUpdateDefaultContributorRole() {
Response createUser = UtilIT.createRandomUser();
Expand Down
205 changes: 205 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/LinkIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package edu.harvard.iq.dataverse.api;

import com.jayway.restassured.RestAssured;
import com.jayway.restassured.path.json.JsonPath;
import com.jayway.restassured.response.Response;
import edu.harvard.iq.dataverse.util.BundleUtil;
import java.util.logging.Logger;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
import static javax.ws.rs.core.Response.Status.OK;
import static org.hamcrest.CoreMatchers.equalTo;
import org.junit.BeforeClass;
import org.junit.Test;

public class LinkIT {

private static final Logger logger = Logger.getLogger(LinkIT.class.getCanonicalName());

@BeforeClass
public static void setUpClass() {
RestAssured.baseURI = UtilIT.getRestAssuredBaseUri();
}

@Test
public void testLinkedDataset() {

Response createUser = UtilIT.createRandomUser();
createUser.prettyPrint();
createUser.then().assertThat()
.statusCode(OK.getStatusCode());
String username = UtilIT.getUsernameFromResponse(createUser);
String apiToken = UtilIT.getApiTokenFromResponse(createUser);

Response createSuperUser = UtilIT.createRandomUser();
createSuperUser.prettyPrint();
createSuperUser.then().assertThat()
.statusCode(OK.getStatusCode());
String superuserUsername = UtilIT.getUsernameFromResponse(createSuperUser);
String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperUser);
Response makeSuperuser = UtilIT.makeSuperUser(superuserUsername);
makeSuperuser.prettyPrint();
makeSuperuser.then().assertThat()
.statusCode(OK.getStatusCode());

Response createDataverse1 = UtilIT.createRandomDataverse(apiToken);
createDataverse1.prettyPrint();
createDataverse1.then().assertThat()
.statusCode(CREATED.getStatusCode());
String dataverse1Alias = UtilIT.getAliasFromResponse(createDataverse1);

Response createDataset = UtilIT.createRandomDatasetViaNativeApi(dataverse1Alias, apiToken);
createDataset.prettyPrint();
createDataset.then().assertThat()
.statusCode(CREATED.getStatusCode());

Integer datasetId = UtilIT.getDatasetIdFromResponse(createDataset);
String datasetPid = JsonPath.from(createDataset.asString()).getString("data.persistentId");

Response createDataverse2 = UtilIT.createRandomDataverse(apiToken);
createDataverse2.prettyPrint();
createDataverse2.then().assertThat()
.statusCode(CREATED.getStatusCode());
String dataverse2Alias = UtilIT.getAliasFromResponse(createDataverse2);
Integer dataverse2Id = UtilIT.getDatasetIdFromResponse(createDataverse2);
String dataverse2Name = JsonPath.from(createDataverse2.asString()).getString("data.name");

UtilIT.publishDataverseViaNativeApi(dataverse1Alias, apiToken).then().assertThat()
.statusCode(OK.getStatusCode());

// You can't link an unpublished dataset.
Response tryToLinkUnpublishedDataset = UtilIT.linkDataset(datasetPid, dataverse2Alias, superuserApiToken);
tryToLinkUnpublishedDataset.prettyPrint();
tryToLinkUnpublishedDataset.then().assertThat()
.statusCode(FORBIDDEN.getStatusCode())
.body("message", equalTo("Can't link a dataset that has not been published or is not harvested"));

UtilIT.publishDatasetViaNativeApi(datasetPid, "major", apiToken).then().assertThat()
.statusCode(OK.getStatusCode());

UtilIT.publishDataverseViaNativeApi(dataverse2Alias, apiToken).then().assertThat()
.statusCode(OK.getStatusCode());

// A dataset cannot be linked to its parent dataverse.
Response tryToLinkToParentDataverse = UtilIT.linkDataset(datasetPid, dataverse1Alias, superuserApiToken);
tryToLinkToParentDataverse.prettyPrint();
tryToLinkToParentDataverse.then().assertThat()
.statusCode(FORBIDDEN.getStatusCode())
.body("message", equalTo("Can't link a dataset to its dataverse"));

// Link dataset to non-parent dataverse (allowed).
Response linkDataset = UtilIT.linkDataset(datasetPid, dataverse2Alias, superuserApiToken);
linkDataset.prettyPrint();
linkDataset.then().assertThat()
.statusCode(OK.getStatusCode());

// A dataset cannot be linked to the same dataverse again.
Response tryToLinkAgain = UtilIT.linkDataset(datasetPid, dataverse2Alias, superuserApiToken);
tryToLinkAgain.prettyPrint();
tryToLinkAgain.then().assertThat()
.statusCode(FORBIDDEN.getStatusCode())
.body("message", equalTo("Can't link a dataset that has already been linked to this dataverse"));
}

@Test
public void testCreateDeleteDataverseLink() {
Response createUser = UtilIT.createRandomUser();

createUser.prettyPrint();
String username = UtilIT.getUsernameFromResponse(createUser);
String apiToken = UtilIT.getApiTokenFromResponse(createUser);

Response superuserResponse = UtilIT.makeSuperUser(username);

Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
createDataverseResponse.prettyPrint();
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
Integer dataverseId = UtilIT.getDataverseIdFromResponse(createDataverseResponse);

Response createDataverseResponse2 = UtilIT.createRandomDataverse(apiToken);
createDataverseResponse2.prettyPrint();
String dataverseAlias2 = UtilIT.getAliasFromResponse(createDataverseResponse2);

Response createLinkingDataverseResponse = UtilIT.createDataverseLink(dataverseAlias, dataverseAlias2, apiToken);
createLinkingDataverseResponse.prettyPrint();
createLinkingDataverseResponse.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.message", equalTo("Dataverse " + dataverseAlias + " linked successfully to " + dataverseAlias2));

Response tryLinkingAgain = UtilIT.createDataverseLink(dataverseAlias, dataverseAlias2, apiToken);
tryLinkingAgain.prettyPrint();
tryLinkingAgain.then().assertThat()
.statusCode(FORBIDDEN.getStatusCode())
.body("message", equalTo(dataverseAlias + " has already been linked to " + dataverseAlias2 + "."));

Response deleteLinkingDataverseResponse = UtilIT.deleteDataverseLink(dataverseAlias, dataverseAlias2, apiToken);
deleteLinkingDataverseResponse.prettyPrint();
deleteLinkingDataverseResponse.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.message", equalTo("Link from Dataverse " + dataverseAlias + " to linked Dataverse " + dataverseAlias2 + " deleted"));
}

@Test
public void testDeepLinks() {
Response createUser = UtilIT.createRandomUser();

createUser.prettyPrint();
String username = UtilIT.getUsernameFromResponse(createUser);
String apiToken = UtilIT.getApiTokenFromResponse(createUser);

Response superuserResponse = UtilIT.makeSuperUser(username);

Response createLevel1a = UtilIT.createSubDataverse(UtilIT.getRandomDvAlias() + "-level1a", null, apiToken, ":root");
createLevel1a.prettyPrint();
String level1a = UtilIT.getAliasFromResponse(createLevel1a);

Response createLevel1b = UtilIT.createSubDataverse(UtilIT.getRandomDvAlias() + "-level1b", null, apiToken, ":root");
createLevel1b.prettyPrint();
String level1b = UtilIT.getAliasFromResponse(createLevel1b);

Response linkLevel1toLevel1 = UtilIT.createDataverseLink(level1a, level1b, apiToken);
linkLevel1toLevel1.prettyPrint();
linkLevel1toLevel1.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.message", equalTo("Dataverse " + level1a + " linked successfully to " + level1b));

Response searchLevel1toLevel1 = UtilIT.search("*", apiToken, "&subtree=" + level1b);
searchLevel1toLevel1.prettyPrint();
searchLevel1toLevel1.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.total_count", equalTo(1))
.body("data.items[0].name", equalTo(level1a));

/**
* Remove this early return when you are ready to work on
* https://github.com/IQSS/dataverse/issues/7430 about strange linking
* behavior.
*/
if (true) {
return;
}

Response createLevel2a = UtilIT.createSubDataverse(UtilIT.getRandomDvAlias() + "-level2a", null, apiToken, level1a);
createLevel2a.prettyPrint();
String level2a = UtilIT.getAliasFromResponse(createLevel2a);

Response createLevel2b = UtilIT.createSubDataverse(UtilIT.getRandomDvAlias() + "-level2b", null, apiToken, level1b);
createLevel2b.prettyPrint();
String level2b = UtilIT.getAliasFromResponse(createLevel2b);

Response linkLevel2toLevel2 = UtilIT.createDataverseLink(level2a, level2b, apiToken);
linkLevel2toLevel2.prettyPrint();
linkLevel2toLevel2.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.message", equalTo("Dataverse " + level2a + " linked successfully to " + level2b));

Response searchLevel2toLevel2 = UtilIT.search("*", apiToken, "&subtree=" + level2b);
searchLevel2toLevel2.prettyPrint();
searchLevel2toLevel2.then().assertThat()
.statusCode(OK.getStatusCode())
.body("data.total_count", equalTo(1))
.body("data.items[0].name", equalTo(level2a));

}

}