From 76a130e5d2be7e1fccac933ec0fb59cf6d4d70f1 Mon Sep 17 00:00:00 2001 From: "Calvin Winkowski (Telnoratti)" Date: Wed, 17 Aug 2016 16:27:19 -0400 Subject: [PATCH 1/7] Fix psql_exec commands to work with different passwords. --- scripts/installer/install | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/installer/install b/scripts/installer/install index 0475c37171f..744f86f0997 100755 --- a/scripts/installer/install +++ b/scripts/installer/install @@ -807,7 +807,7 @@ else print TMPCMD $sql_command; close TMPCMD; - my $psql_commandline = $psql_exec . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -U postgres -d postgres -f /tmp/pgcmd.$$.tmp >/dev/null 2>&1"; + my $psql_commandline = $psql_admin_exec . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -U postgres -d postgres -f /tmp/pgcmd.$$.tmp >/dev/null 2>&1"; my $out = qx($psql_commandline 2>&1); my $exitcode = $?; @@ -829,8 +829,8 @@ else print "\nCreating Postgres database:\n"; my $psql_command = - $psql_admin_exec - . "/createdb -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -U postgres " + $psql_exec + . "/createdb -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -U dvnapp " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . " --owner=" . $CONFIG_DEFAULTS{'POSTGRES_USER'}; From 330d3590af0b35504431412843d1d3b82db300dd Mon Sep 17 00:00:00 2001 From: bmckinney Date: Fri, 16 Sep 2016 11:57:06 -0400 Subject: [PATCH 2/7] adds ability to get and set dataverseType via son --- .../harvard/iq/dataverse/util/json/JsonParser.java | 11 ++++++++++- .../harvard/iq/dataverse/util/json/JsonPrinter.java | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java index 3e8a6152558..3a91fa74f23 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java @@ -95,7 +95,16 @@ public Dataverse parseDataverse(JsonObject jobj) throws JsonParseException { dv.setDataverseTheme(theme); theme.setDataverse(dv); } - + + dv.setDataverseType(Dataverse.DataverseType.UNCATEGORIZED); // default + if (jobj.containsKey("dataverseType")) { + for (Dataverse.DataverseType dvtype : Dataverse.DataverseType.values()) { + if (dvtype.name().equalsIgnoreCase(jobj.getString("dataverseType"))) { + dv.setDataverseType(dvtype); + } + } + } + /* We decided that subject is not user set, but gotten from the subject of the dataverse's datasets - leavig this code in for now, in case we need to go back to it at some point diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index f00bee0b140..9b11f1a9525 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -173,7 +173,8 @@ public static JsonObjectBuilder json(Dataverse dv) { .add("affiliation", dv.getAffiliation()) .add("dataverseContacts", json(dv.getDataverseContacts())) .add("permissionRoot", dv.isPermissionRoot()) - .add("description", dv.getDescription()); + .add("description", dv.getDescription()) + .add("dataverseType", dv.getDataverseType().name()); if (dv.getOwner() != null) { bld.add("ownerId", dv.getOwner().getId()); } From 203966f5a46e02fc7b50da10b6499ff2af949d43 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Wed, 21 Sep 2016 14:00:05 -0400 Subject: [PATCH 3/7] add more tests for setting dv category via API #3371 Also, be more strict. Require ALL CAPS. We can always loosen this later. --- .../iq/dataverse/util/json/JsonParser.java | 2 +- .../iq/dataverse/api/DataversesIT.java | 83 ++++++++++++------- .../harvard/iq/dataverse/api/SearchIT.java | 41 --------- .../edu/harvard/iq/dataverse/api/UtilIT.java | 11 ++- .../dataverse/util/json/JsonParserTest.java | 3 + .../resources/json/complete-dataverse.json | 1 + 6 files changed, 64 insertions(+), 77 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java index 3a91fa74f23..0130bf81979 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java @@ -99,7 +99,7 @@ public Dataverse parseDataverse(JsonObject jobj) throws JsonParseException { dv.setDataverseType(Dataverse.DataverseType.UNCATEGORIZED); // default if (jobj.containsKey("dataverseType")) { for (Dataverse.DataverseType dvtype : Dataverse.DataverseType.values()) { - if (dvtype.name().equalsIgnoreCase(jobj.getString("dataverseType"))) { + if (dvtype.name().equals(jobj.getString("dataverseType"))) { dv.setDataverseType(dvtype); } } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java index 2d243e9bb50..e7227321146 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -2,39 +2,32 @@ import com.jayway.restassured.RestAssured; import com.jayway.restassured.response.Response; +import edu.harvard.iq.dataverse.Dataverse; import java.util.logging.Logger; -import org.junit.AfterClass; +import javax.ws.rs.core.Response.Status; import org.junit.BeforeClass; import org.junit.Test; import static junit.framework.Assert.assertEquals; +import static org.hamcrest.CoreMatchers.equalTo; public class DataversesIT { private static final Logger logger = Logger.getLogger(DataversesIT.class.getCanonicalName()); - private static String username1; - private static String apiToken1; - private static String dataverseAlias1; - private static String dataverseAlias2; - @BeforeClass public static void setUpClass() { - RestAssured.baseURI = UtilIT.getRestAssuredBaseUri(); - - Response createUserResponse = UtilIT.createRandomUser(); -// createUserResponse.prettyPrint(); - assertEquals(200, createUserResponse.getStatusCode()); - - apiToken1 = UtilIT.getApiTokenFromResponse(createUserResponse); - username1 = UtilIT.getUsernameFromResponse(createUserResponse); - } @Test public void testAttemptToCreateDuplicateAlias() throws Exception { - Response createDataverse1Response = UtilIT.createRandomDataverse(apiToken1); + Response createUser = UtilIT.createRandomUser(); +// createUser.prettyPrint(); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + + Response createDataverse1Response = UtilIT.createRandomDataverse(apiToken); if (createDataverse1Response.getStatusCode() != 201) { // purposefully using println here to the error shows under "Test Results" in Netbeans System.out.println("A workspace for testing (a dataverse) couldn't be created in the root dataverse. The output was:\n\n" + createDataverse1Response.body().asString()); @@ -44,36 +37,62 @@ public void testAttemptToCreateDuplicateAlias() throws Exception { } assertEquals(201, createDataverse1Response.getStatusCode()); - dataverseAlias1 = UtilIT.getAliasFromResponse(createDataverse1Response); - dataverseAlias2 = dataverseAlias1.toUpperCase(); + String dataverseAlias1 = UtilIT.getAliasFromResponse(createDataverse1Response); + String dataverseAlias2 = dataverseAlias1.toUpperCase(); logger.info("Attempting to creating dataverse with alias '" + dataverseAlias2 + "' (uppercase version of existing '" + dataverseAlias1 + "' dataverse, should fail)..."); - Response attemptToCreateDataverseWithDuplicateAlias = UtilIT.createDataverse(dataverseAlias2, apiToken1); + String category = null; + Response attemptToCreateDataverseWithDuplicateAlias = UtilIT.createDataverse(dataverseAlias2, category, apiToken); attemptToCreateDataverseWithDuplicateAlias.prettyPrint(); assertEquals(400, attemptToCreateDataverseWithDuplicateAlias.getStatusCode()); logger.info("Deleting dataverse " + dataverseAlias1); - Response deleteDataverse1Response = UtilIT.deleteDataverse(dataverseAlias1, apiToken1); + Response deleteDataverse1Response = UtilIT.deleteDataverse(dataverseAlias1, apiToken); deleteDataverse1Response.prettyPrint(); assertEquals(200, deleteDataverse1Response.getStatusCode()); logger.info("Checking response code for attempting to delete a non-existent dataverse."); - Response attemptToDeleteDataverseThatShouldNotHaveBeenCreated = UtilIT.deleteDataverse(dataverseAlias2, apiToken1); + Response attemptToDeleteDataverseThatShouldNotHaveBeenCreated = UtilIT.deleteDataverse(dataverseAlias2, apiToken); attemptToDeleteDataverseThatShouldNotHaveBeenCreated.prettyPrint(); assertEquals(404, attemptToDeleteDataverseThatShouldNotHaveBeenCreated.getStatusCode()); } - @AfterClass - public static void tearDownClass() { - boolean disabled = false; - - if (disabled) { - return; - } - - Response deleteUser1Response = UtilIT.deleteUser(username1); - deleteUser1Response.prettyPrint(); - assertEquals(200, deleteUser1Response.getStatusCode()); + @Test + public void dataverseCategory() { + Response createUser = UtilIT.createRandomUser(); + createUser.prettyPrint(); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + + Response createDataverseWithoutCategory = UtilIT.createRandomDataverse(apiToken); + createDataverseWithoutCategory.prettyPrint(); + createDataverseWithoutCategory.then().assertThat() + .body("data.dataverseType", equalTo("UNCATEGORIZED")) + .statusCode(Status.CREATED.getStatusCode()); + + String alias1 = UtilIT.getRandomIdentifier(); + String category1 = Dataverse.DataverseType.LABORATORY.toString(); + Response createDataverseWithCategory = UtilIT.createDataverse(alias1, category1, apiToken); + createDataverseWithCategory.prettyPrint(); + createDataverseWithCategory.then().assertThat() + .body("data.dataverseType", equalTo("LABORATORY")) + .statusCode(Status.CREATED.getStatusCode()); + + String alias2 = UtilIT.getRandomIdentifier(); + String madeUpCategory = "madeUpCategory"; + Response createDataverseWithInvalidCategory = UtilIT.createDataverse(alias2, madeUpCategory, apiToken); + createDataverseWithInvalidCategory.prettyPrint(); + createDataverseWithInvalidCategory.then().assertThat() + .body("data.dataverseType", equalTo("UNCATEGORIZED")) + .statusCode(Status.CREATED.getStatusCode()); + + String alias3 = UtilIT.getRandomIdentifier(); + String category3 = Dataverse.DataverseType.LABORATORY.toString().toLowerCase(); + Response createDataverseWithLowerCaseCategory = UtilIT.createDataverse(alias3, category3, apiToken); + createDataverseWithLowerCaseCategory.prettyPrint(); + createDataverseWithLowerCaseCategory.then().assertThat() + .body("data.dataverseType", equalTo("UNCATEGORIZED")) + .statusCode(Status.CREATED.getStatusCode()); } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java b/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java index 5cc8bb17ddb..ae5f8ec7182 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/SearchIT.java @@ -73,7 +73,6 @@ public class SearchIT { private static TestUser homer; private static TestUser ned; private static TestUser clancy; - private static final String categoryTestDataverse = "categoryTestDataverse"; private static final String dvForPermsTesting = "dvForPermsTesting"; private static String dataset1; private static String dataset2; @@ -89,7 +88,6 @@ public class SearchIT { private static final boolean disableTestPermsonRootDv = false; private static final boolean disableTestPermsOnNewDv = false; private static final boolean homerPublishesVersion2AfterDeletingFile = false; - private static final boolean disableTestCategory = false; private Stopwatch timer; private boolean haveToUseCurlForUpload = false; @@ -731,40 +729,6 @@ public void homerPublishesVersion2AfterDeletingFile() throws InterruptedExceptio } - @Ignore - @Test - public void dataverseCategory() { - - if (disableTestCategory) { - return; - } - - Response enableNonPublicSearch = enableSetting(SettingsServiceBean.Key.SearchApiNonPublicAllowed); - assertEquals(200, enableNonPublicSearch.getStatusCode()); - - /** - * Unfortunately, it appears that the ability to specify the category of - * a dataverse when creating it is a GUI-only feature. It can't - * currently be done via the API, to our knowledge. You also can't tell - * from the API which category was persisted but it always seems to be - * "UNCATEGORIZED" - */ - TestDataverse dataverseToCreate = new TestDataverse(categoryTestDataverse, categoryTestDataverse, Dataverse.DataverseType.ORGANIZATIONS_INSTITUTIONS); - Response createDvResponse = createDataverse(dataverseToCreate, homer); - assertEquals(201, createDvResponse.getStatusCode()); - - TestSearchQuery query = new TestSearchQuery(categoryTestDataverse); - Response searchResponse = search(query, homer); -// searchResponse.prettyPrint(); - JsonPath jsonPath = JsonPath.from(searchResponse.body().asString()); - String category = jsonPath.get("data.facets." + SearchFields.DATAVERSE_CATEGORY).toString(); - String msg = "category: " + category; - assertEquals("category: [null]", msg); - - Response disableNonPublicSearch = deleteSetting(SettingsServiceBean.Key.SearchApiNonPublicAllowed); - assertEquals(200, disableNonPublicSearch.getStatusCode()); - } - @AfterClass public static void cleanup() { @@ -805,11 +769,6 @@ public static void cleanup() { assertEquals(200, destroyDataset.getStatusCode()); } - if (!disableTestCategory) { - Response deleteCategoryDataverseResponse = deleteDataverse(categoryTestDataverse, homer); - assertEquals(200, deleteCategoryDataverseResponse.getStatusCode()); - } - if (!disableTestPermsOnNewDv) { Response deleteDvResponse = deleteDataverse(dvForPermsTesting, homer); assertEquals(200, deleteDvResponse.getStatusCode()); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 6fefbdcd8a7..ef24d5da3bf 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -20,7 +20,9 @@ import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import static com.jayway.restassured.RestAssured.given; import static com.jayway.restassured.path.xml.XmlPath.from; +import java.math.BigDecimal; import java.util.List; +import javax.json.JsonValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -85,7 +87,7 @@ private static String getRandomUsername() { return "user" + getRandomIdentifier().substring(0, 8); } - private static String getRandomIdentifier() { + public static String getRandomIdentifier() { return UUID.randomUUID().toString().substring(0, 8); } @@ -133,7 +135,7 @@ public static Response getServiceDocument(String apiToken) { return response; } - static Response createDataverse(String alias, String apiToken) { + static Response createDataverse(String alias, String category, String apiToken) { JsonArrayBuilder contactArrayBuilder = Json.createArrayBuilder(); contactArrayBuilder.add(Json.createObjectBuilder().add("contactEmail", getEmailFromUserName(getRandomIdentifier()))); JsonArrayBuilder subjectArrayBuilder = Json.createArrayBuilder(); @@ -143,6 +145,8 @@ static Response createDataverse(String alias, String apiToken) { .add("name", alias) .add("dataverseContacts", contactArrayBuilder) .add("dataverseSubjects", subjectArrayBuilder) + // don't send "dataverseType" if category is null, must be a better way + .add(category != null ? "dataverseType" : "notTheKeyDataverseType", category != null ? category : "whatever") .build(); Response createDataverseResponse = given() .body(dvData.toString()).contentType(ContentType.JSON) @@ -152,7 +156,8 @@ static Response createDataverse(String alias, String apiToken) { static Response createRandomDataverse(String apiToken) { String alias = getRandomIdentifier(); - return createDataverse(alias, apiToken); + String category = null; + return createDataverse(alias, category, apiToken); } static Response showDataverseContents(String alias, String apiToken) { diff --git a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java index 8a6b945a710..c80ef237ba6 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java @@ -239,6 +239,7 @@ public void testParseCompleteDataverse() throws JsonParseException { assertEquals("testAlias", actual.getAlias()); assertEquals("Test-Driven University", actual.getAffiliation()); assertEquals("test Description.", actual.getDescription()); + assertEquals("LABORATORY", actual.getDataverseType().toString()); assertEquals(2, actual.getDataverseContacts().size()); assertEquals("test@example.com,test@example.org", actual.getContactEmails()); assertEquals(0, actual.getDataverseContacts().get(0).getDisplayOrder()); @@ -261,6 +262,7 @@ public void testParseThemeDataverse() throws JsonParseException { assertEquals("testAlias", actual.getAlias()); assertEquals("Test-Driven University", actual.getAffiliation()); assertEquals("test Description.", actual.getDescription()); + assertEquals("UNCATEGORIZED", actual.getDataverseType().toString()); assertEquals("gray", actual.getDataverseTheme().getBackgroundColor()); assertEquals("red", actual.getDataverseTheme().getLinkColor()); assertEquals("http://www.cnn.com", actual.getDataverseTheme().getLinkUrl()); @@ -292,6 +294,7 @@ public void testParseMinimalDataverse() throws JsonParseException { Dataverse actual = sut.parseDataverse(dvJson); assertEquals("testDv", actual.getName()); assertEquals("testAlias", actual.getAlias()); + assertEquals("UNCATEGORIZED", actual.getDataverseType().toString()); assertTrue(actual.getDataverseContacts().isEmpty()); assertEquals("", actual.getContactEmails()); assertFalse(actual.isPermissionRoot()); diff --git a/src/test/resources/json/complete-dataverse.json b/src/test/resources/json/complete-dataverse.json index 98679af44ff..3e3056f2e74 100644 --- a/src/test/resources/json/complete-dataverse.json +++ b/src/test/resources/json/complete-dataverse.json @@ -11,5 +11,6 @@ } ], "permissionRoot": true, + "dataverseType": "LABORATORY", "description": "test Description." } From e8d19b36fb51c321a80cc0dff482cbcd6ba3a35c Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Sep 2016 09:46:22 -0400 Subject: [PATCH 4/7] Put maintenance page back in branch #2588 This reverts commit be727595f7797f6b9290f31b65595e49fb710d4c. --- .../etc/maintenance/HarvardShield_RGB.png | Bin 0 -> 15728 bytes .../files/etc/maintenance/maintenance.xhtml | 118 ++++++++++++++++++ .../source/installation/administration.rst | 7 ++ 3 files changed, 125 insertions(+) create mode 100644 doc/sphinx-guides/source/_static/installation/files/etc/maintenance/HarvardShield_RGB.png create mode 100644 doc/sphinx-guides/source/_static/installation/files/etc/maintenance/maintenance.xhtml diff --git a/doc/sphinx-guides/source/_static/installation/files/etc/maintenance/HarvardShield_RGB.png b/doc/sphinx-guides/source/_static/installation/files/etc/maintenance/HarvardShield_RGB.png new file mode 100644 index 0000000000000000000000000000000000000000..f8fd03c2aa8a05e61994c165443aa93bdd3510ef GIT binary patch literal 15728 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 + + + + Harvard Dataverse + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ +
+ Harvard Dataverse +
+
+ A collaboration with Harvard Library, Harvard University IT, and IQSS +
+
+
+
+
+
+

We apologize for the service interruption.

+

The Harvard Dataverse is currently undergoing maintenance. At this time both the application and APIs are not able to be used. However, the datasets stored in the Harvard Dataverse are fine and not impacted by this maintenance.

+

If you have any comments, questions or concerns, please reach out to support@dataverse.org.

+
+
+ + + diff --git a/doc/sphinx-guides/source/installation/administration.rst b/doc/sphinx-guides/source/installation/administration.rst index 59cf11652a3..b2f908bd8f1 100644 --- a/doc/sphinx-guides/source/installation/administration.rst +++ b/doc/sphinx-guides/source/installation/administration.rst @@ -67,6 +67,13 @@ https://github.com/IQSS/dataverse/issues/2595 contains some information on enabl There is a database table called ``actionlogrecord`` that captures events that may be of interest. See https://github.com/IQSS/dataverse/issues/2729 for more discussion around this table. +Maintenance +---------- + +When you have scheduled down time for your production servers, we provide a `sample maintenance page <../_static/installation/files/etc/maintenance/maintenance.xhtml>`_ for you to use. To download, right-click and select "Save Link As". + +The maintenance page is intended to be a static page served by Apache to provide users with a nicer, more informative experience when the site is unavailable. + User Administration ------------------- From d315204aa08c0141141b78cc547b05d77c1e9098 Mon Sep 17 00:00:00 2001 From: "Calvin Winkowski (Telnoratti)" Date: Tue, 27 Sep 2016 12:43:45 -0400 Subject: [PATCH 5/7] Use CONFIG_DEFAULTS for postgres user. --- scripts/installer/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/installer/install b/scripts/installer/install index 744f86f0997..8e1008ec997 100755 --- a/scripts/installer/install +++ b/scripts/installer/install @@ -830,7 +830,7 @@ else my $psql_command = $psql_exec - . "/createdb -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -U dvnapp " + . "/createdb -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -U $CONFIG_DEFAULTS{'POSTGRES_USER'} " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . " --owner=" . $CONFIG_DEFAULTS{'POSTGRES_USER'}; From 1ebd12a4b402db9edc4930b9df9b122b953b1cf2 Mon Sep 17 00:00:00 2001 From: Michael Heppler Date: Thu, 6 Oct 2016 16:02:32 -0400 Subject: [PATCH 6/7] Added missing links to Appendix and Account Creation & Management pgs, plus fixed screenshot image widths on Dataverse Management pg in User Guides. [ref #3023] --- .../source/user/dataverse-management.rst | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/sphinx-guides/source/user/dataverse-management.rst b/doc/sphinx-guides/source/user/dataverse-management.rst index bac42305119..b3a1d7e95f1 100755 --- a/doc/sphinx-guides/source/user/dataverse-management.rst +++ b/doc/sphinx-guides/source/user/dataverse-management.rst @@ -12,7 +12,7 @@ to manage the settings described in this guide. Create a Dataverse (Within the "Root" Dataverse) =================================================== -Creating a dataverse is easy but first you must be a registered user (see Create Account). +Creating a dataverse is easy but first you must be a registered user (see :doc:`/user/account`). #. Once you are logged in click on the "Add Data" button and in the dropdown menu select "New Dataverse". #. Once on the "New Dataverse" page fill in the following fields: @@ -22,7 +22,7 @@ Creating a dataverse is easy but first you must be a registered user (see Create * **Affiliation**: Add any Affiliation that can be associated to this particular dataverse (e.g., project name, institute name, department name, journal name, etc). This is automatically filled out if you have added an affiliation for your user account. * **Description**: Provide a description of this dataverse. This will display on the home page of your dataverse and in the search result list. The description field supports certain HTML tags (, ,
,
, , ,
,
,
, ,
,

-

, , , ,
  • ,
      ,

      ,

      , , , , , , 
        ). * **Category**: Select a category that best describes the type of dataverse this will be. For example, if this is a dataverse for an individual researcher's datasets, select Researcher. If this is a dataverse for an institution, select Organization & Institution. - * **Choose the sets of Metadata Elements for datasets in this dataverse**: by default the metadata elements will be from the host dataverse that this new dataverse is created in. Dataverse offers metadata standards for multiple domains. To learn more about the metadata standards in Dataverse please check out the appendix (insert link here) + * **Choose the sets of Metadata Elements for datasets in this dataverse**: by default the metadata elements will be from the host dataverse that this new dataverse is created in. Dataverse offers metadata standards for multiple domains. To learn more about the metadata standards in Dataverse please check out the :doc:`/user/appendix`. * **Select facets for this dataverse**: by default the facets that will appear on your dataverse landing page will be from the host dataverse that this new dataverse was created in. The facets are simply metadata fields that can be used to help others easily find dataverses and datasets within this dataverse. You can select as many facets as you would like. #. Selected metadata elements are also used to pick which metadata fields you would like to use for creating templates for your datasets. Metadata fields can be hidden, or selected as required or optional. Once you have selected all the fields you would like to use, you can create your template(s) after you finish creating your dataverse. #. Click "Create Dataverse" button and you're done! @@ -92,19 +92,24 @@ Permissions When you access a dataverse's permissions page, you will see there are three sections: Permissions, Users/Groups, and Roles. |image2| + Clicking on Permissions will bring you to this page: + |image3| + By clicking on the Edit Access button, you are able to change the settings allowing no one or anyone to add either dataverses or datasets to a dataverse. + |image4| + The Edit Access pop up allows you to also select if someone adding a dataset to this dataverse should be allowed to publish it (Curator role) or if the dataset will be submitted to the administrator of this dataverse to be reviewed then published (Contributor role). These Access settings can be changed at any time. Assign Role ----------------------- -You can also give access to a Dataverse user to allow them to access an unpublished dataverse as well as other roles. To do this, click on the Assign Roles to Users/Groups button in the Users/Groups section. You can also give multiple users the same role at one time. +You can also give access to a Dataverse user to allow them to access an unpublished dataverse as well as other roles. To do this, click on the Assign Roles to Users/Groups button in the Users/Groups section. You can also give multiple users the same role at one time. This roles can be removed at any time. + |image5| -|image6| -This roles can be removed at any time. +|image6| .. _dataset-templates: @@ -176,10 +181,15 @@ is made public, it can no longer be unpublished. .. |image1| image:: ./img/Dataverse-Diagram.png .. |image2| image:: ./img/dvperms1.png + :class: img-responsive .. |image3| image:: ./img/dv2.png + :class: img-responsive .. |image4| image:: ./img/dv3.png + :class: img-responsive .. |image5| image:: ./img/dv4.png + :class: img-responsive .. |image6| image:: ./img/dv5.png + :class: img-responsive From 510b907fecc1d04a902cea1a472145dc5d066f5c Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Fri, 14 Oct 2016 14:36:09 -0400 Subject: [PATCH 7/7] Document JSON required to create a dataverse #3371 Also expose database constraint violations via API. --- .../_static/api/dataverse-complete.json | 15 +++++++ .../source/_static/api/dataverse-minimal.json | 9 ++++ doc/sphinx-guides/source/api/native-api.rst | 15 ++++++- .../harvard/iq/dataverse/api/Dataverses.java | 19 +++++++++ .../iq/dataverse/util/json/JsonParser.java | 7 ++++ .../iq/dataverse/api/DataversesIT.java | 42 ++++++++++++++++++- .../edu/harvard/iq/dataverse/api/UtilIT.java | 7 ++++ .../dataverse/util/json/JsonParserTest.java | 22 ++++++---- .../resources/json/complete-dataverse.json | 16 ------- 9 files changed, 126 insertions(+), 26 deletions(-) create mode 100644 doc/sphinx-guides/source/_static/api/dataverse-complete.json create mode 100644 doc/sphinx-guides/source/_static/api/dataverse-minimal.json delete mode 100644 src/test/resources/json/complete-dataverse.json diff --git a/doc/sphinx-guides/source/_static/api/dataverse-complete.json b/doc/sphinx-guides/source/_static/api/dataverse-complete.json new file mode 100644 index 00000000000..d5e92d1f1fc --- /dev/null +++ b/doc/sphinx-guides/source/_static/api/dataverse-complete.json @@ -0,0 +1,15 @@ +{ + "name": "Scientific Research", + "alias": "science", + "dataverseContacts": [ + { + "contactEmail": "pi@example.edu" + }, + { + "contactEmail": "student@example.edu" + } + ], + "affiliation": "Scientific Research University", + "description": "We do all the science.", + "dataverseType": "LABORATORY" +} diff --git a/doc/sphinx-guides/source/_static/api/dataverse-minimal.json b/doc/sphinx-guides/source/_static/api/dataverse-minimal.json new file mode 100644 index 00000000000..10086749825 --- /dev/null +++ b/doc/sphinx-guides/source/_static/api/dataverse-minimal.json @@ -0,0 +1,9 @@ +{ + "name": "Scientific Research", + "alias": "science", + "dataverseContacts": [ + { + "contactEmail": "pi@example.edu" + } + ] +} diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 8b686df66cd..2b0d52aa969 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -12,11 +12,24 @@ Endpoints Dataverses ~~~~~~~~~~~ -Generates a new dataverse under ``$id``. Expects a json content describing the dataverse. +Generates a new dataverse under ``$id``. Expects a JSON content describing the dataverse, as in the example below. If ``$id`` is omitted, a root dataverse is created. ``$id`` can either be a dataverse id (long) or a dataverse alias (more robust). :: POST http://$SERVER/api/dataverses/$id?key=$apiKey +The following JSON example can be `downloaded <../_static/api/dataverse-complete.json>`_ and modified to create dataverses to suit your needs. The fields ``name``, ``alias``, and ``dataverseContacts`` are required. The controlled vocabulary for ``dataverseType`` is + +- ``JOURNALS`` +- ``LABORATORY`` +- ``ORGANIZATIONS_INSTITUTIONS`` +- ``RESEARCHERS`` +- ``RESEARCH_GROUP`` +- ``RESEARCH_PROJECTS`` +- ``TEACHING_COURSES`` +- ``UNCATEGORIZED`` + +.. literalinclude:: ../_static/api/dataverse-complete.json + View data about the dataverse identified by ``$id``. ``$id`` can be the id number of the dataverse, its alias, or the special value ``:root``. :: GET http://$SERVER/api/dataverses/$id diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java index 3c676f5d665..cf03e6936d4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Dataverses.java @@ -130,6 +130,25 @@ public Response addDataverse( String body, @PathParam("identifier") String paren d = execCommand( new CreateDataverseCommand(d, createDataverseRequest(u), null, null) ); return createdResponse( "/dataverses/"+d.getAlias(), json(d) ); } catch ( WrappedResponse ww ) { + Throwable cause = ww.getCause(); + StringBuilder sb = new StringBuilder(); + while (cause.getCause() != null) { + cause = cause.getCause(); + if (cause instanceof ConstraintViolationException) { + ConstraintViolationException constraintViolationException = (ConstraintViolationException) cause; + for (ConstraintViolation violation : constraintViolationException.getConstraintViolations()) { + sb.append(" Invalid value: <<<").append(violation.getInvalidValue()).append(">>> for ") + .append(violation.getPropertyPath()).append(" at ") + .append(violation.getLeafBean()).append(" - ") + .append(violation.getMessage()); + } + } + } + String error = sb.toString(); + if (!error.isEmpty()) { + LOGGER.log(Level.INFO, error); + return ww.refineResponse(error); + } return ww.getResponse(); } catch (EJBException ex) { diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java index aadaccb86d8..8d1253d0131 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java @@ -75,6 +75,13 @@ public void setLenient(boolean lenient) { public Dataverse parseDataverse(JsonObject jobj) throws JsonParseException { Dataverse dv = new Dataverse(); + /** + * @todo Instead of this getMandatoryString method we should run the + * String through ConstraintValidator. See EMailValidatorTest and + * EMailValidator for examples. That way we can check not only if it's + * required or not but other bean validation rules such as "must match + * this regex". + */ dv.setAlias(getMandatoryString(jobj, "alias")); dv.setName(getMandatoryString(jobj, "name")); dv.setDescription(jobj.getString("description", null)); diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java index e7227321146..9d4e82b125b 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -3,8 +3,15 @@ import com.jayway.restassured.RestAssured; import com.jayway.restassured.response.Response; import edu.harvard.iq.dataverse.Dataverse; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.util.logging.Logger; +import javax.json.Json; +import javax.json.JsonObject; import javax.ws.rs.core.Response.Status; +import static javax.ws.rs.core.Response.Status.CREATED; +import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; +import static javax.ws.rs.core.Response.Status.OK; import org.junit.BeforeClass; import org.junit.Test; import static junit.framework.Assert.assertEquals; @@ -58,7 +65,7 @@ public void testAttemptToCreateDuplicateAlias() throws Exception { } @Test - public void dataverseCategory() { + public void testDataverseCategory() { Response createUser = UtilIT.createRandomUser(); createUser.prettyPrint(); String username = UtilIT.getUsernameFromResponse(createUser); @@ -96,4 +103,37 @@ public void dataverseCategory() { } + @Test + public void testMinimalDataverse() throws FileNotFoundException { + Response createUser = UtilIT.createRandomUser(); + createUser.prettyPrint(); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + JsonObject dvJson; + FileReader reader = new FileReader("doc/sphinx-guides/source/_static/api/dataverse-minimal.json"); + dvJson = Json.createReader(reader).readObject(); + Response create = UtilIT.createDataverse(dvJson, apiToken); + create.prettyPrint(); + create.then().assertThat().statusCode(CREATED.getStatusCode()); + Response deleteDataverse = UtilIT.deleteDataverse("science", apiToken); + deleteDataverse.prettyPrint(); + deleteDataverse.then().assertThat().statusCode(OK.getStatusCode()); + } + + @Test + public void testNotEnoughJson() { + Response createUser = UtilIT.createRandomUser(); + createUser.prettyPrint(); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + Response createFail = UtilIT.createDataverse(Json.createObjectBuilder().add("name", "notEnough").add("alias", "notEnough").build(), apiToken); + createFail.prettyPrint(); + createFail.then().assertThat() + /** + * @todo We really don't want Dataverse to throw a 500 error + * when not enough JSON is supplied to create a dataverse. + */ + .statusCode(INTERNAL_SERVER_ERROR.getStatusCode()); + } + } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index ef24d5da3bf..d64e2fabd05 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -154,6 +154,13 @@ static Response createDataverse(String alias, String category, String apiToken) return createDataverseResponse; } + static Response createDataverse(JsonObject dvData, String apiToken) { + Response createDataverseResponse = given() + .body(dvData.toString()).contentType(ContentType.JSON) + .when().post("/api/dataverses/:root?key=" + apiToken); + return createDataverseResponse; + } + static Response createRandomDataverse(String apiToken) { String alias = getRandomIdentifier(); String category = null; diff --git a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java index b9279cfd46a..11c33ad97d9 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java @@ -22,6 +22,7 @@ import edu.harvard.iq.dataverse.authorization.users.GuestUser; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -236,20 +237,25 @@ public void testPrimitiveRepeatesFieldRoundTrip() throws JsonParseException { public void testParseCompleteDataverse() throws JsonParseException { JsonObject dvJson; - try (InputStream jsonFile = ClassLoader.getSystemResourceAsStream("json/complete-dataverse.json")) { - InputStreamReader reader = new InputStreamReader(jsonFile, "UTF-8"); + try (FileReader reader = new FileReader("doc/sphinx-guides/source/_static/api/dataverse-complete.json")) { dvJson = Json.createReader(reader).readObject(); Dataverse actual = sut.parseDataverse(dvJson); - assertEquals("testDv", actual.getName()); - assertEquals("testAlias", actual.getAlias()); - assertEquals("Test-Driven University", actual.getAffiliation()); - assertEquals("test Description.", actual.getDescription()); + assertEquals("Scientific Research", actual.getName()); + assertEquals("science", actual.getAlias()); + assertEquals("Scientific Research University", actual.getAffiliation()); + assertEquals("We do all the science.", actual.getDescription()); assertEquals("LABORATORY", actual.getDataverseType().toString()); assertEquals(2, actual.getDataverseContacts().size()); - assertEquals("test@example.com,test@example.org", actual.getContactEmails()); + assertEquals("pi@example.edu,student@example.edu", actual.getContactEmails()); assertEquals(0, actual.getDataverseContacts().get(0).getDisplayOrder()); assertEquals(1, actual.getDataverseContacts().get(1).getDisplayOrder()); - assertTrue(actual.isPermissionRoot()); + /** + * The JSON does not specify "permissionRoot" because it's a no-op + * so we don't want to document it in the API Guide. It's a no-op + * because as of fb7e65f (4.0) all dataverses have permissionRoot + * hard coded to true. + */ + assertFalse(actual.isPermissionRoot()); } catch (IOException ioe) { throw new JsonParseException("Couldn't read test file", ioe); } diff --git a/src/test/resources/json/complete-dataverse.json b/src/test/resources/json/complete-dataverse.json deleted file mode 100644 index 3e3056f2e74..00000000000 --- a/src/test/resources/json/complete-dataverse.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "testDv", - "alias": "testAlias", - "affiliation": "Test-Driven University", - "dataverseContacts": [ - { - "contactEmail": "test@example.com" - }, - { - "contactEmail": "test@example.org" - } - ], - "permissionRoot": true, - "dataverseType": "LABORATORY", - "description": "test Description." -}