From f08788e40d3652dd762bf9905ecf912cbccb8031 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Wed, 31 May 2017 17:30:10 -0400 Subject: [PATCH 01/91] Beginning of user list api endpoint for #3614 --- .../harvard/iq/dataverse/UserServiceBean.java | 110 ++++++++++++++++++ .../edu/harvard/iq/dataverse/api/Admin.java | 42 +++++++ 2 files changed, 152 insertions(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index c88fee426b3..0bb67db29c3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -1,13 +1,20 @@ package edu.harvard.iq.dataverse; +import com.google.gson.Gson; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.search.IndexServiceBean; +import java.util.HashSet; +import java.util.List; import java.util.logging.Logger; import javax.ejb.EJB; import javax.ejb.Stateless; import javax.inject.Named; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import javax.persistence.Query; @Stateless @Named @@ -34,5 +41,108 @@ public AuthenticatedUser save( AuthenticatedUser user ) { return user; } + + + /** + * + * @param searchKey + * @param sortKey + * @param resultLimit + * @return + */ + public JsonObjectBuilder getUserListAsJSON(String searchKey, String sortKey, Integer resultLimit) { + System.out.println("getUserListAsJSON 1"); + + List userResults = getUserList(searchKey, sortKey, resultLimit); + System.out.println("getUserListAsJSON 2"); + + if ((userResults==null)||(userResults.isEmpty())){ + return null; + } + + /* + u.id, u.useridentifier,"; + qstr += " u.lastname, u.firstname, u.email,"; + qstr += " u.affiliation, u.superuser,"; + qstr += " u.position, u.modificationtime"; + qstr += " FROM authenticateduser u"; + */ + JsonArrayBuilder jsonArray = Json.createArrayBuilder(); + for (Object[] result : userResults) { + JsonObjectBuilder jsonData = Json.createObjectBuilder(); + jsonData.add("id", (int)result[0]) + .add("userIdentifier", (String)result[1]) + .add("lastName", (String)result[2]) + .add("firstName", (String)result[3]) + .add("email", (String)result[4]); + //jsonData.add("affiliation", (boolean)result[5]); + //jsonData.add("superuser", (boolean)result[6]); + jsonArray.add(jsonData); + } + + JsonObjectBuilder jsonUserData = Json.createObjectBuilder(); + jsonUserData.add("userCount", userResults.size()) + .add("users", jsonArray); + + + System.out.println("getUserListAsJSON 3: " + userResults.size()); + + + return jsonUserData; + + + } + + + /** + * + * @param searchKey + * @param sortKey + * @param resultLimit + * @return + */ + public List getUserList(String searchKey, String sortKey, Integer resultLimit) { + + if ((sortKey == null) || (sortKey.isEmpty())){ + sortKey = "u.username"; + }else{ + sortKey = "u." + sortKey; + } + + if ((resultLimit == null)||(resultLimit < 25)){ + resultLimit = 25; + } + + if ((searchKey==null)||(searchKey.isEmpty())){ + searchKey = ""; + } + + + String qstr = "SELECT u.id, u.useridentifier,"; + qstr += " u.lastname, u.firstname, u.email,"; + qstr += " u.affiliation, u.superuser,"; + qstr += " u.position, u.modificationtime"; + qstr += " FROM authenticateduser u"; + /*qstr += " WHERE u.useridentifier ILIKE ':searchKey%'"; + qstr += " OR u.firstname ILIKE ':searchKey%'"; + qstr += " OR u.lastname ILIKE ':searchKey%'";*/ + qstr += " ORDER BY u.useridentifier"; + qstr += " LIMIT " + resultLimit; + + System.out.println("--------------\n\n" + qstr); + + Query nativeQuery = em.createNativeQuery(qstr); + //nativeQuery.setParameter("searchKey", searchKey); + //nativeQuery.setParameter(2, searchKey); + //nativeQuery.setParameter(3, searchKey); + //nativeQuery.setParameter(4, sortKey); + + System.out.println("--------------\n\n" + nativeQuery.toString()); + + + return nativeQuery.getResultList(); + + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index b145cdca1d2..d54858e38f1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -4,8 +4,10 @@ import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.DataverseSession; import edu.harvard.iq.dataverse.DvObject; import edu.harvard.iq.dataverse.EMailValidator; +import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.actionlogging.ActionLogRecord; import edu.harvard.iq.dataverse.api.dto.RoleDTO; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; @@ -57,6 +59,7 @@ import edu.harvard.iq.dataverse.authorization.users.User; import edu.harvard.iq.dataverse.dataset.DatasetThumbnail; import edu.harvard.iq.dataverse.dataset.DatasetUtil; +import javax.inject.Inject; import javax.ws.rs.QueryParam; /** * Where the secure, setup API calls live. @@ -74,6 +77,13 @@ public class Admin extends AbstractApiBean { ShibServiceBean shibService; @EJB AuthTestDataServiceBean authTestDataService; + @EJB + UserServiceBean userService; + + // Make the session available + @Inject + DataverseSession session; + @Path("settings") @GET @@ -291,7 +301,39 @@ public Response listAuthenticatedUsers() { return ok(userArray); } + + @GET + @Path("list-users") + @Produces({"application/json"}) + public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String userIdentifier) { + System.out.println("_YE_OLDE_QUERY_COUNTER_"); + + boolean DEBUG_MODE = true; + + + AuthenticatedUser authUser = null; + + if (DEBUG_MODE==true){ // DEBUG: use userIdentifier + + //return ok("hello! (debug)"); + + } else if ((session.getUser() != null)&&(session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())){ + + authUser = (AuthenticatedUser)session.getUser(); + + }else{ + return error(Response.Status.FORBIDDEN, "forbidden, please leave"); + } + + JsonObjectBuilder userList = userService.getUserListAsJSON(null, null, 25); + if (userList == null){ + return ok("no users found!"); + } + return ok(userList); + } + + /** * @todo Make this support creation of BuiltInUsers. * From 4df733ca153dcc2503175fd9625f99dc49285fc8 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 10:02:55 -0400 Subject: [PATCH 02/91] #3614 work on the initial native query for user info excluding roles for now --- .../harvard/iq/dataverse/UserServiceBean.java | 93 ++++++++++++++----- .../edu/harvard/iq/dataverse/api/Admin.java | 15 ++- 2 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 0bb67db29c3..5904def7069 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -3,6 +3,9 @@ import com.google.gson.Gson; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.search.IndexServiceBean; +import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; +import java.math.BigDecimal; +import java.sql.Timestamp; import java.util.HashSet; import java.util.List; import java.util.logging.Logger; @@ -12,6 +15,7 @@ import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; +import javax.json.JsonValue; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; @@ -43,6 +47,33 @@ public AuthenticatedUser save( AuthenticatedUser user ) { } + /** + * Convenience method to format dbResult + * @param dbResult + * @return + */ + private String getStringOrNull(Object dbResult){ + + if (dbResult == null){ + return null; + } + return (String)dbResult; + } + + /** + * Convenience method to format dbResult + * @param dbResult + * @return + */ + private String getTimestampStringOrNull(Object dbResult){ + + if (dbResult == null){ + return null; + } + return ((Timestamp)dbResult).toString(); + } + + /** * * @param searchKey @@ -53,41 +84,52 @@ public AuthenticatedUser save( AuthenticatedUser user ) { public JsonObjectBuilder getUserListAsJSON(String searchKey, String sortKey, Integer resultLimit) { System.out.println("getUserListAsJSON 1"); + // ------------------------------------------------- + // Retrieve a list of user attributes from a native query + // ------------------------------------------------- List userResults = getUserList(searchKey, sortKey, resultLimit); - System.out.println("getUserListAsJSON 2"); + // ------------------------------------------------- + // Initialize the overall JSON response object (jsonUserData) + // as well as the JSOn user List + // ------------------------------------------------- + JsonObjectBuilder jsonUserData = Json.createObjectBuilder(); + JsonArrayBuilder jsonUserListArray = Json.createArrayBuilder(); + + // ------------------------------------------------- + // No results..... Return count of 0 and empty array + // ------------------------------------------------- if ((userResults==null)||(userResults.isEmpty())){ - return null; + jsonUserData.add("userCount", 0) + .add("users", jsonUserListArray); + return jsonUserData; } - /* - u.id, u.useridentifier,"; - qstr += " u.lastname, u.firstname, u.email,"; - qstr += " u.affiliation, u.superuser,"; - qstr += " u.position, u.modificationtime"; - qstr += " FROM authenticateduser u"; - */ - JsonArrayBuilder jsonArray = Json.createArrayBuilder(); - for (Object[] result : userResults) { - JsonObjectBuilder jsonData = Json.createObjectBuilder(); - jsonData.add("id", (int)result[0]) + // ------------------------------------------------- + // We have results, format them into a JSON object + // ------------------------------------------------- + for (Object[] result : userResults) { + + // not putting explicit nulls for now b/c https://stackoverflow.com/questions/22363925/jsr-353-how-to-add-null-values-using-javax-json-jsonobjectbuilder + // + NullSafeJsonBuilder singleUserData = NullSafeJsonBuilder.jsonObjectBuilder(); + + singleUserData.add("id", (int)result[0]) .add("userIdentifier", (String)result[1]) - .add("lastName", (String)result[2]) - .add("firstName", (String)result[3]) - .add("email", (String)result[4]); - //jsonData.add("affiliation", (boolean)result[5]); - //jsonData.add("superuser", (boolean)result[6]); - jsonArray.add(jsonData); + .add("lastName", this.getStringOrNull(result[2])) + .add("firstName", this.getStringOrNull(result[3])) + .add("email", this.getStringOrNull(result[4])) + .add("affiliation", this.getStringOrNull(result[5])) + .add("is_superuser", (boolean)result[6]) + .add("position", this.getStringOrNull(result[7])) + .add("modificationTime", this.getTimestampStringOrNull(result[8])); + jsonUserListArray.add(singleUserData); } - JsonObjectBuilder jsonUserData = Json.createObjectBuilder(); jsonUserData.add("userCount", userResults.size()) - .add("users", jsonArray); - - - System.out.println("getUserListAsJSON 3: " + userResults.size()); - + .add("users", jsonUserListArray); + return jsonUserData; @@ -95,6 +137,7 @@ public JsonObjectBuilder getUserListAsJSON(String searchKey, String sortKey, Int } + /** * * @param searchKey diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index d54858e38f1..bc52b0a79c2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -59,6 +59,7 @@ import edu.harvard.iq.dataverse.authorization.users.User; import edu.harvard.iq.dataverse.dataset.DatasetThumbnail; import edu.harvard.iq.dataverse.dataset.DatasetUtil; +import edu.harvard.iq.dataverse.util.StringUtil; import javax.inject.Inject; import javax.ws.rs.QueryParam; /** @@ -305,12 +306,12 @@ public Response listAuthenticatedUsers() { @GET @Path("list-users") @Produces({"application/json"}) - public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String userIdentifier) { + public Response filterAuthenticatedUsers(@QueryParam("q") String searchTerm, + @QueryParam("numDisplay") Integer itemsPerPage) { System.out.println("_YE_OLDE_QUERY_COUNTER_"); boolean DEBUG_MODE = true; - AuthenticatedUser authUser = null; if (DEBUG_MODE==true){ // DEBUG: use userIdentifier @@ -326,7 +327,15 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String userId } - JsonObjectBuilder userList = userService.getUserListAsJSON(null, null, 25); + if ((searchTerm == null) || (searchTerm.trim().isEmpty())){ + searchTerm = null; + } + if ((itemsPerPage == null) || (itemsPerPage < 10)){ + itemsPerPage = 25; + } + String sortKey = null; + + JsonObjectBuilder userList = userService.getUserListAsJSON(searchTerm, sortKey , itemsPerPage); if (userList == null){ return ok("no users found!"); } From 92701e3621bd0a41e72c960388f1a51df6f43a0a Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 10:17:05 -0400 Subject: [PATCH 03/91] #3614, filter param for basic query --- .../harvard/iq/dataverse/UserServiceBean.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 5904def7069..b6654353f83 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -161,27 +161,26 @@ public List getUserList(String searchKey, String sortKey, Integer resu searchKey = ""; } + + System.out.println("Search key: " + searchKey); String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; qstr += " u.affiliation, u.superuser,"; qstr += " u.position, u.modificationtime"; qstr += " FROM authenticateduser u"; - /*qstr += " WHERE u.useridentifier ILIKE ':searchKey%'"; - qstr += " OR u.firstname ILIKE ':searchKey%'"; - qstr += " OR u.lastname ILIKE ':searchKey%'";*/ + qstr += " WHERE u.useridentifier ILIKE #searchKey"; + qstr += " OR u.firstname ILIKE #searchKey"; + qstr += " OR u.lastname ILIKE #searchKey"; + //qstr += " WHERE u.useridentifier = #searchKey"; + qstr += " ORDER BY u.useridentifier"; qstr += " LIMIT " + resultLimit; System.out.println("--------------\n\n" + qstr); Query nativeQuery = em.createNativeQuery(qstr); - //nativeQuery.setParameter("searchKey", searchKey); - //nativeQuery.setParameter(2, searchKey); - //nativeQuery.setParameter(3, searchKey); - //nativeQuery.setParameter(4, sortKey); - - System.out.println("--------------\n\n" + nativeQuery.toString()); + nativeQuery.setParameter("searchKey", searchKey + "%"); return nativeQuery.getResultList(); From 85d79791ad20ec44bc927accf208cd4b4a0587ae Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 11:15:27 -0400 Subject: [PATCH 04/91] move biz logic to another class #3614 --- .../harvard/iq/dataverse/UserServiceBean.java | 96 +++++++++----- .../edu/harvard/iq/dataverse/api/Admin.java | 23 ++-- .../iq/dataverse/userdata/UserListMaker.java | 121 ++++++++++++++++++ 3 files changed, 195 insertions(+), 45 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index b6654353f83..f30c611fa31 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -76,39 +76,30 @@ private String getTimestampStringOrNull(Object dbResult){ /** * - * @param searchKey + * @param searchTerm * @param sortKey * @param resultLimit * @return */ - public JsonObjectBuilder getUserListAsJSON(String searchKey, String sortKey, Integer resultLimit) { + public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Integer resultLimit, Integer offset) { System.out.println("getUserListAsJSON 1"); // ------------------------------------------------- // Retrieve a list of user attributes from a native query // ------------------------------------------------- - List userResults = getUserList(searchKey, sortKey, resultLimit); - - - // ------------------------------------------------- - // Initialize the overall JSON response object (jsonUserData) - // as well as the JSOn user List - // ------------------------------------------------- - JsonObjectBuilder jsonUserData = Json.createObjectBuilder(); - JsonArrayBuilder jsonUserListArray = Json.createArrayBuilder(); + List userResults = getUserList(searchTerm, sortKey, resultLimit, offset); // ------------------------------------------------- // No results..... Return count of 0 and empty array // ------------------------------------------------- if ((userResults==null)||(userResults.isEmpty())){ - jsonUserData.add("userCount", 0) - .add("users", jsonUserListArray); - return jsonUserData; + return Json.createArrayBuilder(); // return an empty array } // ------------------------------------------------- // We have results, format them into a JSON object // ------------------------------------------------- + JsonArrayBuilder jsonUserListArray = Json.createArrayBuilder(); for (Object[] result : userResults) { // not putting explicit nulls for now b/c https://stackoverflow.com/questions/22363925/jsr-353-how-to-add-null-values-using-javax-json-jsonobjectbuilder @@ -126,13 +117,8 @@ public JsonObjectBuilder getUserListAsJSON(String searchKey, String sortKey, Int .add("modificationTime", this.getTimestampStringOrNull(result[8])); jsonUserListArray.add(singleUserData); } - - jsonUserData.add("userCount", userResults.size()) - .add("users", jsonUserListArray); - - - return jsonUserData; - + + return jsonUserListArray; } @@ -140,12 +126,12 @@ public JsonObjectBuilder getUserListAsJSON(String searchKey, String sortKey, Int /** * - * @param searchKey + * @param searchTerm * @param sortKey * @param resultLimit * @return */ - public List getUserList(String searchKey, String sortKey, Integer resultLimit) { + public List getUserList(String searchTerm, String sortKey, Integer resultLimit, Integer offset) { if ((sortKey == null) || (sortKey.isEmpty())){ sortKey = "u.username"; @@ -157,34 +143,80 @@ public List getUserList(String searchKey, String sortKey, Integer resu resultLimit = 25; } - if ((searchKey==null)||(searchKey.isEmpty())){ - searchKey = ""; + if ((searchTerm==null)||(searchTerm.isEmpty())){ + searchTerm = ""; + } + + if ((offset == null)||(offset < 0)){ + offset = 0; } - System.out.println("Search key: " + searchKey); + System.out.println("Search key: " + searchTerm); String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; qstr += " u.affiliation, u.superuser,"; qstr += " u.position, u.modificationtime"; qstr += " FROM authenticateduser u"; - qstr += " WHERE u.useridentifier ILIKE #searchKey"; - qstr += " OR u.firstname ILIKE #searchKey"; - qstr += " OR u.lastname ILIKE #searchKey"; - //qstr += " WHERE u.useridentifier = #searchKey"; - + qstr += " WHERE "; + qstr += getSharedSearchClause(); qstr += " ORDER BY u.useridentifier"; qstr += " LIMIT " + resultLimit; + qstr += " OFFSET " + offset; + qstr += ";"; System.out.println("--------------\n\n" + qstr); Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchKey", searchKey + "%"); + nativeQuery.setParameter("searchTerm", searchTerm + "%"); return nativeQuery.getResultList(); } + /** + * The search clause needs to be consistent between the searches that: + * (1) get a user count + * (2) get a list of users + * + * @param searchTerm + * @return + */ + private String getSharedSearchClause(){ + + String searchClause = " u.useridentifier ILIKE #searchTerm"; + searchClause += " OR u.firstname ILIKE #searchTerm"; + searchClause += " OR u.lastname ILIKE #searchTerm"; + + return searchClause; + } + + /** + * + * @param searchTerm + * @return + */ + public Long getUserCount(String searchTerm) { + + if ((searchTerm==null)||(searchTerm.isEmpty())){ + searchTerm = ""; + } + + String qstr = "SELECT count(u.id)"; + qstr += " FROM authenticateduser u"; + qstr += " WHERE "; + qstr += getSharedSearchClause(); + qstr += ";"; + + Query nativeQuery = em.createNativeQuery(qstr); + nativeQuery.setParameter("searchTerm", searchTerm + "%"); + + return (Long)nativeQuery.getSingleResult(); + + } + + + } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index bc52b0a79c2..f6b15d71450 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -59,6 +59,7 @@ import edu.harvard.iq.dataverse.authorization.users.User; import edu.harvard.iq.dataverse.dataset.DatasetThumbnail; import edu.harvard.iq.dataverse.dataset.DatasetUtil; +import edu.harvard.iq.dataverse.userdata.UserListMaker; import edu.harvard.iq.dataverse.util.StringUtil; import javax.inject.Inject; import javax.ws.rs.QueryParam; @@ -307,7 +308,10 @@ public Response listAuthenticatedUsers() { @Path("list-users") @Produces({"application/json"}) public Response filterAuthenticatedUsers(@QueryParam("q") String searchTerm, - @QueryParam("numDisplay") Integer itemsPerPage) { + @QueryParam("numDisplay") Integer itemsPerPage, + @QueryParam("selectedPage") Integer selectedPage, + @QueryParam("sortKey") String sortKey + ) { System.out.println("_YE_OLDE_QUERY_COUNTER_"); boolean DEBUG_MODE = true; @@ -326,20 +330,13 @@ public Response filterAuthenticatedUsers(@QueryParam("q") String searchTerm, return error(Response.Status.FORBIDDEN, "forbidden, please leave"); } + //return ok("hey"); - if ((searchTerm == null) || (searchTerm.trim().isEmpty())){ - searchTerm = null; - } - if ((itemsPerPage == null) || (itemsPerPage < 10)){ - itemsPerPage = 25; - } - String sortKey = null; + UserListMaker userListMaker = new UserListMaker(userService); - JsonObjectBuilder userList = userService.getUserListAsJSON(searchTerm, sortKey , itemsPerPage); - if (userList == null){ - return ok("no users found!"); - } - return ok(userList); + JsonObjectBuilder userInfo = userListMaker.runSearch(searchTerm, itemsPerPage, selectedPage, null); + + return ok(userInfo); } diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java new file mode 100644 index 00000000000..cb935a62d12 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -0,0 +1,121 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.userdata; + +import edu.harvard.iq.dataverse.UserServiceBean; +import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; +import java.util.List; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObjectBuilder; + +/** + * + * @author rmp553 + */ +public class UserListMaker { + + UserServiceBean userService; + + public boolean errorFound = false; + public String errorMessage = null; + + /* + * Constructor + */ + public UserListMaker(UserServiceBean userService) { + this.msgt("MyDataFinder, constructor"); + this.userService = userService; + } + + /* + * Run the search + */ + public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Integer selectedPage, String sorKey){ + + // Initialize searchTerm + if ((searchTerm == null) || (searchTerm.trim().isEmpty())){ + searchTerm = null; + } + + // Initialize itemsPerPage + if ((itemsPerPage == null) || (itemsPerPage < 10)){ + itemsPerPage = 25; + } + + // Initialize selectedPage + if ((selectedPage == null) || (selectedPage < 1)){ + selectedPage = 1; + } + + // Initialize sortKey + String sortKey = null; + + + // ------------------------------------------------- + // (1) What is the user count for this search? + // ------------------------------------------------- + Long userCount = userService.getUserCount(searchTerm); + + // Are there any hits? No; return info + if ((userCount == null)||(userCount == 0)){ + return getNoResultsJSON(); + } + + // ------------------------------------------------- + // (2) Do some calculations here regarding the selected page, offset, etc. + // ------------------------------------------------- + + // e.g Are there enough results to justify the selected page, etc. + + // ------------------------------------------------- + // (3) Retrieve the users + // ------------------------------------------------- + JsonArrayBuilder jsonUserListArray = userService.getUserListAsJSON(searchTerm, sortKey, itemsPerPage, 0); + if (jsonUserListArray==null){ + return getNoResultsJSON(); + } + + JsonObjectBuilder jsonOverallData = Json.createObjectBuilder(); + jsonOverallData.add("userCount", userCount) + .add("users", jsonUserListArray) + .add("selectedPage", 1); + + return jsonOverallData; + + } + + private JsonObjectBuilder getNoResultsJSON(){ + + return Json.createObjectBuilder() + .add("userCount", 0) + .add("users", Json.createArrayBuilder()) // empty array + .add("selectedPage", 1); + } + + public boolean hasError(){ + return this.errorFound; + } + + public String getErrorMessage(){ + return this.errorMessage; + } + + private void addErrorMessage(String errMsg){ + this.errorFound = true; + this.errorMessage = errMsg; + } + + private void msg(String s){ + System.out.println(s); + } + + private void msgt(String s){ + msg("-------------------------------"); + msg(s); + msg("-------------------------------"); + } +} From 4b98b381513c0a53cc78c0ab4a0e0eef4fcd3942 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 11:53:57 -0400 Subject: [PATCH 05/91] #3614 pagination working for api call. example url with 14k+ users http://localhost:8080/api/admin/list-users?&numDisplay=25&q=&selectedPage=50 --- .../edu/harvard/iq/dataverse/api/Admin.java | 2 +- .../iq/dataverse/userdata/UserListMaker.java | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index f6b15d71450..c282322732b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -308,8 +308,8 @@ public Response listAuthenticatedUsers() { @Path("list-users") @Produces({"application/json"}) public Response filterAuthenticatedUsers(@QueryParam("q") String searchTerm, - @QueryParam("numDisplay") Integer itemsPerPage, @QueryParam("selectedPage") Integer selectedPage, + @QueryParam("numDisplay") Integer itemsPerPage, @QueryParam("sortKey") String sortKey ) { System.out.println("_YE_OLDE_QUERY_COUNTER_"); diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index cb935a62d12..91f359b4a33 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -6,6 +6,8 @@ package edu.harvard.iq.dataverse.userdata; import edu.harvard.iq.dataverse.UserServiceBean; +import edu.harvard.iq.dataverse.mydata.Pager; +import edu.harvard.iq.dataverse.search.SearchConstants; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.util.List; import javax.json.Json; @@ -23,6 +25,9 @@ public class UserListMaker { public boolean errorFound = false; public String errorMessage = null; + public static final int ITEMS_PER_PAGE = 25; + + /* * Constructor */ @@ -43,7 +48,7 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte // Initialize itemsPerPage if ((itemsPerPage == null) || (itemsPerPage < 10)){ - itemsPerPage = 25; + itemsPerPage = ITEMS_PER_PAGE; } // Initialize selectedPage @@ -69,18 +74,28 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte // (2) Do some calculations here regarding the selected page, offset, etc. // ------------------------------------------------- - // e.g Are there enough results to justify the selected page, etc. + int offset = (selectedPage - 1) * itemsPerPage; + if (offset > userCount){ + offset = 0; + selectedPage = 1; + } + // ------------------------------------------------- // (3) Retrieve the users // ------------------------------------------------- - JsonArrayBuilder jsonUserListArray = userService.getUserListAsJSON(searchTerm, sortKey, itemsPerPage, 0); + + + JsonArrayBuilder jsonUserListArray = userService.getUserListAsJSON(searchTerm, sortKey, itemsPerPage, offset); if (jsonUserListArray==null){ return getNoResultsJSON(); } + + Pager pager = new Pager(userCount.intValue(), itemsPerPage, selectedPage); JsonObjectBuilder jsonOverallData = Json.createObjectBuilder(); jsonOverallData.add("userCount", userCount) + .add("pagination", pager.asJsonObjectBuilder()) .add("users", jsonUserListArray) .add("selectedPage", 1); From 8864bfc57121764e55fec4d71f1530645b88ab04 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 14:51:12 -0400 Subject: [PATCH 06/91] #3614 basic UI w/ @pdurbin's basic .xhtml page/properties. need to hookup the pager --- src/main/java/Bundle.properties | 4 + .../harvard/iq/dataverse/UserServiceBean.java | 7 +- .../edu/harvard/iq/dataverse/api/Admin.java | 7 +- .../dashboard/DashboardUsersPage.java | 50 +++++++++ .../iq/dataverse/userdata/UserListMaker.java | 6 +- src/main/webapp/dashboard-users.xhtml | 57 ++++++++++ .../webapp/mydata_templates/user_list.html | 27 +++++ .../webapp/resources/js/dashboard_users.js | 100 ++++++++++++++++++ 8 files changed, 251 insertions(+), 7 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java create mode 100644 src/main/webapp/dashboard-users.xhtml create mode 100644 src/main/webapp/mydata_templates/user_list.html create mode 100644 src/main/webapp/resources/js/dashboard_users.js diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 5c3fd33a754..790ed8d23e3 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1631,3 +1631,7 @@ citationFrame.banner.message.here=here citationFrame.banner.closeIcon=Close this message, go to dataset citationFrame.banner.countdownMessage= This message will close in citationFrame.banner.countdownMessage.seconds=seconds + +dashboard.card.users.header=Users +dashboard.card.users.message=List and manage users. +dashboard.card.users.btn.manage=Manage Users \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index f30c611fa31..71c001deae9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -112,7 +112,7 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int .add("firstName", this.getStringOrNull(result[3])) .add("email", this.getStringOrNull(result[4])) .add("affiliation", this.getStringOrNull(result[5])) - .add("is_superuser", (boolean)result[6]) + .add("isSuperuser", (boolean)result[6]) .add("position", this.getStringOrNull(result[7])) .add("modificationTime", this.getTimestampStringOrNull(result[8])); jsonUserListArray.add(singleUserData); @@ -139,8 +139,8 @@ public List getUserList(String searchTerm, String sortKey, Integer res sortKey = "u." + sortKey; } - if ((resultLimit == null)||(resultLimit < 25)){ - resultLimit = 25; + if ((resultLimit == null)||(resultLimit < 1)){ + resultLimit = 1; } if ((searchTerm==null)||(searchTerm.isEmpty())){ @@ -189,6 +189,7 @@ private String getSharedSearchClause(){ String searchClause = " u.useridentifier ILIKE #searchTerm"; searchClause += " OR u.firstname ILIKE #searchTerm"; searchClause += " OR u.lastname ILIKE #searchTerm"; + searchClause += " OR u.email ILIKE #searchTerm"; return searchClause; } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index c282322732b..f36509f4932 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -86,6 +86,9 @@ public class Admin extends AbstractApiBean { @Inject DataverseSession session; + public static final String listUsersPartialAPIPath = "list-users"; + public static final String listUsersFullAPIPath = "/api/v1/admin/" + listUsersPartialAPIPath; + @Path("settings") @GET @@ -305,9 +308,9 @@ public Response listAuthenticatedUsers() { @GET - @Path("list-users") + @Path(listUsersPartialAPIPath) @Produces({"application/json"}) - public Response filterAuthenticatedUsers(@QueryParam("q") String searchTerm, + public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String searchTerm, @QueryParam("selectedPage") Integer selectedPage, @QueryParam("numDisplay") Integer itemsPerPage, @QueryParam("sortKey") String sortKey diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java new file mode 100644 index 00000000000..0efe5832a6f --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -0,0 +1,50 @@ +package edu.harvard.iq.dataverse.dashboard; + +import edu.harvard.iq.dataverse.DataverseSession; +import edu.harvard.iq.dataverse.PermissionsWrapper; +import edu.harvard.iq.dataverse.api.Admin; +import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; +import edu.harvard.iq.dataverse.authorization.DataverseRolePermissionHelper; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.mydata.MyDataFilterParams; +import java.util.List; +import java.util.logging.Logger; +import javax.ejb.EJB; +import javax.faces.context.FacesContext; +import javax.faces.view.ViewScoped; +import javax.inject.Inject; +import javax.inject.Named; +import javax.servlet.http.HttpServletRequest; + +@ViewScoped +@Named("DashboardUsersPage") +public class DashboardUsersPage implements java.io.Serializable { + + private static final Logger logger = Logger.getLogger(DashboardUsersPage.class.getCanonicalName()); + private AuthenticatedUser authUser = null; + + @EJB + AuthenticationServiceBean authenticationService; + + @Inject + DataverseSession session; + @Inject + PermissionsWrapper permissionsWrapper; + + public String init() { + + if ((session.getUser() != null) && (session.getUser().isAuthenticated())&& (session.getUser().isSuperuser())) { + authUser = (AuthenticatedUser) session.getUser(); + } else { + return permissionsWrapper.notAuthorized(); + // redirect to login OR give some type ‘you must be logged in message' + } + + return null; + } + public String getListUsersAPIPath(){ + //return "ok"; + return Admin.listUsersFullAPIPath; + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index 91f359b4a33..1b71a41d8d6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -9,6 +9,7 @@ import edu.harvard.iq.dataverse.mydata.Pager; import edu.harvard.iq.dataverse.search.SearchConstants; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; +import java.math.BigDecimal; import java.util.List; import javax.json.Json; import javax.json.JsonArrayBuilder; @@ -28,6 +29,7 @@ public class UserListMaker { public static final int ITEMS_PER_PAGE = 25; + /* * Constructor */ @@ -97,8 +99,8 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte jsonOverallData.add("userCount", userCount) .add("pagination", pager.asJsonObjectBuilder()) .add("users", jsonUserListArray) - .add("selectedPage", 1); - + .add("selectedPage", 1) + ; return jsonOverallData; } diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml new file mode 100644 index 00000000000..26c6a537793 --- /dev/null +++ b/src/main/webapp/dashboard-users.xhtml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+
+
+ +
+
+
+
+
+ + + + + +
+ +
+
+
+ diff --git a/src/main/webapp/mydata_templates/user_list.html b/src/main/webapp/mydata_templates/user_list.html new file mode 100644 index 00000000000..2e4a0f487c0 --- /dev/null +++ b/src/main/webapp/mydata_templates/user_list.html @@ -0,0 +1,27 @@ + + +{#


{{ data.userCount }} User{% if data.userCount > 1 or data.userCount == 0 %}s{% endif %} found.

#} + + + + + + + + + + + + + {% for name_info in data.users -%} + + + + + + + + + {% endfor %} + +
 username Last Name First Name Email Is Superuser?
{{ loop.index }}{{ name_info.userIdentifier }}{{ name_info.lastName }}{{ name_info.firstName }}{{ name_info.email }}{{ name_info.isSuperuser }}
diff --git a/src/main/webapp/resources/js/dashboard_users.js b/src/main/webapp/resources/js/dashboard_users.js new file mode 100644 index 00000000000..7db6f04c324 --- /dev/null +++ b/src/main/webapp/resources/js/dashboard_users.js @@ -0,0 +1,100 @@ + +var USER_LIST_DEBUG_ON = true; + +function initPage(){ + nunjucks.configure({ autoescape: true }); + bindReturnKeyOnSearch(); + runRegularSearch(); +} + +function clearUserList(){ + $('#div-user-list').html(''); +} + +function clearWarningMessage(){ + $('#div-result-message').html(''); +} + +function setWarningAlert(alert_msg){ + var alert_html = ''; + $('#div-result-message').html(alert_html); +} + +function runRegularSearch(){ + + clearWarningMessage(); + clearUserList(); + + //var selectedPage = $("#selectedPage").val(); + //var searchTerm = $("#searchTerm").val(); + var formData = $("#selectedPage").serialize() + '&' + $("#searchTerm").serialize(); + + // Call the API endpoint + $.getJSON( RETRIEVE_USER_DATA_API_PATH + '?' + formData, function(data) { + + // For debugging, show the returned JSON + if (USER_LIST_DEBUG_ON){ + $("#div-json-results").html(JSON.stringify(data)); + } + + // Didn't work, show error + if ((!data.status)||(!data.status == 'OK')){ + setWarningAlert(data.errorMessage); + return; + } + + // Looks good, let's make a page + + // -------------------------------- + // (3) If JSON has pagination info, make a pager + // -------------------------------- + updatePagination(data); + + // -------------------------------- + // (4) Let's list the users + // -------------------------------- + // pass the list of names to the template + var user_list_html = nunjucks.render('mydata_templates/user_list.html', data); + $("#div-user-list").html(user_list_html); + + }); +} + + +function updatePagination(json_data){ + // console.log(json_data); + if (json_data.data.hasOwnProperty('pagination')){ + var pagination_json = json_data.data.pagination; + // Use nunjucks to create the pagination HTML + var pagination_html = nunjucks.render('mydata_templates/pagination.html', pagination_json); + // Put the pagination HTML into the div + $("#div-pagination").html(pagination_html); + + bindPages(); + } +} + +//----------------------------------------- +// Bind pager buttons +//----------------------------------------- +function bindPages(){ + // bind pager buttons + $("a.page_link").click(function(evt) { + evt.preventDefault(); // stop link from using href + var page_num = $(this).attr('rel'); + $("#selected_page").val(page_num); // update the selected page in the form + runRegularSearch(); // run search + }); +} + +function bindReturnKeyOnSearch(){ + + // Capture pressing return in search box + $('#searchTerm').keypress(function(e) { + if (e.which == '13') { + e.preventDefault(); + $("#selectedPage").val('1'); + runRegularSearch(); + } + }); +} From aafa1c189db881611a49baefaf026b255812c315 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 14:57:08 -0400 Subject: [PATCH 07/91] #3614 paging working, fast but abrupt --- src/main/webapp/dashboard-users.xhtml | 2 +- src/main/webapp/mydata_templates/pagination.html | 2 +- src/main/webapp/resources/js/dashboard_users.js | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 26c6a537793..68079ad9e03 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -33,7 +33,7 @@
-
+
diff --git a/src/main/webapp/mydata_templates/pagination.html b/src/main/webapp/mydata_templates/pagination.html index 42900b4b0fe..ba52b29b9d9 100644 --- a/src/main/webapp/mydata_templates/pagination.html +++ b/src/main/webapp/mydata_templates/pagination.html @@ -14,7 +14,7 @@ {% endif %} {% if endCardNumber > startCardNumber %} - Displaying: {{ startCardNumber }} to {{ endCardNumber }} +
Displaying: {{ startCardNumber }} to {{ endCardNumber }} {% endif %}
diff --git a/src/main/webapp/resources/js/dashboard_users.js b/src/main/webapp/resources/js/dashboard_users.js index 7db6f04c324..a71073a2cba 100644 --- a/src/main/webapp/resources/js/dashboard_users.js +++ b/src/main/webapp/resources/js/dashboard_users.js @@ -1,5 +1,5 @@ -var USER_LIST_DEBUG_ON = true; +var USER_LIST_DEBUG_ON = false; function initPage(){ nunjucks.configure({ autoescape: true }); @@ -63,6 +63,7 @@ function runRegularSearch(){ function updatePagination(json_data){ // console.log(json_data); + $("#div-pagination").html(''); if (json_data.data.hasOwnProperty('pagination')){ var pagination_json = json_data.data.pagination; // Use nunjucks to create the pagination HTML @@ -82,7 +83,7 @@ function bindPages(){ $("a.page_link").click(function(evt) { evt.preventDefault(); // stop link from using href var page_num = $(this).attr('rel'); - $("#selected_page").val(page_num); // update the selected page in the form + $("#selectedPage").val(page_num); // update the selected page in the form runRegularSearch(); // run search }); } From d2bcdd94b3f113f7039be94d3da88241f554ee20 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 15:03:26 -0400 Subject: [PATCH 08/91] basics are in #3614 --- .../harvard/iq/dataverse/MailServiceBean.java | 5 +++- src/main/webapp/dashboard-users.xhtml | 5 +++- .../webapp/mydata_templates/user_list.html | 30 +++++++++---------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java index e09be0ddcf7..f1ec1795519 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java @@ -101,6 +101,8 @@ public void sendMail(String host, String from, String to, String subject, String private Session session; public boolean sendSystemEmail(String to, String subject, String messageText) { + if (true) return true; + boolean sent = false; String body = messageText + ResourceBundle.getBundle("Bundle").getString("notification.email.closing"); logger.fine("Sending email to " + to + ". Subject: <<<" + subject + ">>>. Body: " + body); @@ -178,7 +180,8 @@ public void sendMail(String from, String to, String subject, String messageText, } } - public Boolean sendNotificationEmail(UserNotification notification){ + public Boolean sendNotificationEmail(UserNotification notification){ + if (true) return true; boolean retval = false; String emailAddress = getUserEmailAddress(notification); if (emailAddress != null){ diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 68079ad9e03..159b14dbaaf 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -33,7 +33,10 @@
-
+
+ +
+
diff --git a/src/main/webapp/mydata_templates/user_list.html b/src/main/webapp/mydata_templates/user_list.html index 2e4a0f487c0..8c8901bb51c 100644 --- a/src/main/webapp/mydata_templates/user_list.html +++ b/src/main/webapp/mydata_templates/user_list.html @@ -1,10 +1,7 @@ - - -{#


{{ data.userCount }} User{% if data.userCount > 1 or data.userCount == 0 %}s{% endif %} found.

#} - + @@ -12,16 +9,19 @@ - - {% for name_info in data.users -%} - - - - - - - - - {% endfor %} + + {% for name_info in data.users -%} + + + + + + + + + {% endfor %}
 cnt username Last Name First Name Is Superuser?
{{ loop.index }}{{ name_info.userIdentifier }}{{ name_info.lastName }}{{ name_info.firstName }}{{ name_info.email }}{{ name_info.isSuperuser }}
{{ loop.index }}{{ name_info.userIdentifier }}{{ name_info.lastName }}{{ name_info.firstName }}{{ name_info.email }}{{ name_info.isSuperuser }}
+ + + From cc045a287a3072242629071273c0681d5a03f974 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 15:35:00 -0400 Subject: [PATCH 09/91] #3614 bundlized table headers, added commas to result number --- src/main/java/Bundle.properties | 7 +++++- .../harvard/iq/dataverse/mydata/Pager.java | 10 ++++++++ .../iq/dataverse/userdata/UserListMaker.java | 23 ++++++++++++++++--- .../webapp/mydata_templates/pagination.html | 3 ++- .../webapp/mydata_templates/user_list.html | 16 ++++++++----- .../webapp/resources/js/dashboard_users.js | 3 ++- 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 790ed8d23e3..ede12fcc743 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1634,4 +1634,9 @@ citationFrame.banner.countdownMessage.seconds=seconds dashboard.card.users.header=Users dashboard.card.users.message=List and manage users. -dashboard.card.users.btn.manage=Manage Users \ No newline at end of file +dashboard.card.users.btn.manage=Manage Users +dashboard.list_users.tbl_header.userIdentifier=User name +dashboard.list_users.tbl_header.lastName=Last Name +dashboard.list_users.tbl_header.firstName=First Name +dashboard.list_users.tbl_header.email=Email +dashboard.list_users.tbl_header.isSuperuser=Is Superuser? diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java index 8e4a71f7883..17f804a1b6d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java @@ -12,8 +12,10 @@ import static java.lang.Math.min; import java.net.URL; import java.net.URLClassLoader; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonBuilderFactory; @@ -316,6 +318,13 @@ public String asJSONString(){ return this.asJsonObjectBuilder().build().toString(); } + + public String addCommasToNumber(int count){ + + return NumberFormat.getNumberInstance(Locale.US).format(count); + } + + public JsonObjectBuilder asJsonObjectBuilder(){ JsonObjectBuilder jsonPageInfo = Json.createObjectBuilder(); @@ -323,6 +332,7 @@ public JsonObjectBuilder asJsonObjectBuilder(){ jsonPageInfo.add("isNecessary", this.isPagerNecessary()) .add("numResults", this.numResults) + .add("numResultsString", this.addCommasToNumber(numResults)) .add("docsPerPage", this.docsPerPage) .add("selectedPageNumber", this.selectedPageNumber) .add("pageCount", this.pageCount) diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index 1b71a41d8d6..d028d4c9349 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -8,9 +8,12 @@ import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.mydata.Pager; import edu.harvard.iq.dataverse.search.SearchConstants; +import edu.harvard.iq.dataverse.util.BundleUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.math.BigDecimal; +import java.text.NumberFormat; import java.util.List; +import java.util.Locale; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; @@ -97,9 +100,10 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte JsonObjectBuilder jsonOverallData = Json.createObjectBuilder(); jsonOverallData.add("userCount", userCount) + .add("selectedPage", 1) .add("pagination", pager.asJsonObjectBuilder()) + .add("bundleStrings", getBundleStrings()) .add("users", jsonUserListArray) - .add("selectedPage", 1) ; return jsonOverallData; @@ -109,8 +113,21 @@ private JsonObjectBuilder getNoResultsJSON(){ return Json.createObjectBuilder() .add("userCount", 0) - .add("users", Json.createArrayBuilder()) // empty array - .add("selectedPage", 1); + .add("selectedPage", 1) + .add("bundleStrings", getBundleStrings()) + .add("users", Json.createArrayBuilder()); // empty array + } + + public JsonObjectBuilder getBundleStrings(){ + + return Json.createObjectBuilder() + .add("userIdentifier", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userIdentifier")) + .add("lastName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastName")) + .add("firstName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.firstName")) + .add("email", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.email")) + .add("isSuperuser", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.isSuperuser")) + ; + } public boolean hasError(){ diff --git a/src/main/webapp/mydata_templates/pagination.html b/src/main/webapp/mydata_templates/pagination.html index ba52b29b9d9..6dbaf85c55a 100644 --- a/src/main/webapp/mydata_templates/pagination.html +++ b/src/main/webapp/mydata_templates/pagination.html @@ -7,7 +7,7 @@

{% if numResults > 1 %} - Found: {{ numResults }} results + Found: {{ numResultsString }} results {% elif numResults == 1 %} Found: 1 result @@ -16,6 +16,7 @@ {% if endCardNumber > startCardNumber %}
Displaying: {{ startCardNumber }} to {{ endCardNumber }} {% endif %} +
{% if isNecessary %} diff --git a/src/main/webapp/mydata_templates/user_list.html b/src/main/webapp/mydata_templates/user_list.html index 8c8901bb51c..973568d4743 100644 --- a/src/main/webapp/mydata_templates/user_list.html +++ b/src/main/webapp/mydata_templates/user_list.html @@ -1,12 +1,12 @@ - - - - - - + + + + + + @@ -19,6 +19,10 @@ + {% else %} + + + {% endfor %}
cntusername Last Name First Name Email Is Superuser?  {{ data.bundleStrings.userIdentifier }}{{ data.bundleStrings.lastName }}{{ data.bundleStrings.firstName }}{{ data.bundleStrings.email }}{{ data.bundleStrings.isSuperuser }}
{{ name_info.email }} {{ name_info.isSuperuser }}
Sorry. No users found.
diff --git a/src/main/webapp/resources/js/dashboard_users.js b/src/main/webapp/resources/js/dashboard_users.js index a71073a2cba..900feeba95a 100644 --- a/src/main/webapp/resources/js/dashboard_users.js +++ b/src/main/webapp/resources/js/dashboard_users.js @@ -1,5 +1,5 @@ -var USER_LIST_DEBUG_ON = false; +var USER_LIST_DEBUG_ON = true; function initPage(){ nunjucks.configure({ autoescape: true }); @@ -57,6 +57,7 @@ function runRegularSearch(){ var user_list_html = nunjucks.render('mydata_templates/user_list.html', data); $("#div-user-list").html(user_list_html); + }); } From a7bde8a8fe77191d29257f68a792c8fd25250a12 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Thu, 1 Jun 2017 15:55:38 -0400 Subject: [PATCH 10/91] add button, counts on dashboard to manage users #3614 --- .../dashboard/DashboardUsersPage.java | 38 ++++++++++++------- src/main/webapp/dashboard.xhtml | 22 +++++++++++ 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 0efe5832a6f..b55ec6977a1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -2,20 +2,15 @@ import edu.harvard.iq.dataverse.DataverseSession; import edu.harvard.iq.dataverse.PermissionsWrapper; +import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.api.Admin; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; -import edu.harvard.iq.dataverse.authorization.DataverseRolePermissionHelper; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; -import edu.harvard.iq.dataverse.engine.command.DataverseRequest; -import edu.harvard.iq.dataverse.mydata.MyDataFilterParams; -import java.util.List; import java.util.logging.Logger; import javax.ejb.EJB; -import javax.faces.context.FacesContext; import javax.faces.view.ViewScoped; import javax.inject.Inject; import javax.inject.Named; -import javax.servlet.http.HttpServletRequest; @ViewScoped @Named("DashboardUsersPage") @@ -27,24 +22,39 @@ public class DashboardUsersPage implements java.io.Serializable { @EJB AuthenticationServiceBean authenticationService; - @Inject - DataverseSession session; + @EJB + UserServiceBean userService; + + @Inject + DataverseSession session; @Inject - PermissionsWrapper permissionsWrapper; - + PermissionsWrapper permissionsWrapper; + public String init() { - - if ((session.getUser() != null) && (session.getUser().isAuthenticated())&& (session.getUser().isSuperuser())) { + + if ((session.getUser() != null) && (session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())) { authUser = (AuthenticatedUser) session.getUser(); } else { return permissionsWrapper.notAuthorized(); - // redirect to login OR give some type ‘you must be logged in message' + // redirect to login OR give some type ‘you must be logged in message' } return null; } - public String getListUsersAPIPath(){ + + public String getListUsersAPIPath() { //return "ok"; return Admin.listUsersFullAPIPath; } + + public long getUserCount() { + String nullSearchTerm = null; + return userService.getUserCount(nullSearchTerm); + } + + public long getSuperUserUserCount() { + // FIXME: Return the actual count of superusers. + return 2l; + } + } diff --git a/src/main/webapp/dashboard.xhtml b/src/main/webapp/dashboard.xhtml index ac170efe593..6d1cb495a6d 100644 --- a/src/main/webapp/dashboard.xhtml +++ b/src/main/webapp/dashboard.xhtml @@ -102,6 +102,28 @@
+
+
+

#{bundle['dashboard.card.users.header']}

+
+
+ +

Users

+
+
+ +

Super-Users

+
+
+ +
+
From 7475cd468ccfdf559b3954834ebee906c81f930f Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Thu, 1 Jun 2017 15:58:57 -0400 Subject: [PATCH 11/91] hide JSON by turning off debugging #3614 --- src/main/webapp/resources/js/dashboard_users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/webapp/resources/js/dashboard_users.js b/src/main/webapp/resources/js/dashboard_users.js index 900feeba95a..f0a8be4f16d 100644 --- a/src/main/webapp/resources/js/dashboard_users.js +++ b/src/main/webapp/resources/js/dashboard_users.js @@ -1,5 +1,5 @@ -var USER_LIST_DEBUG_ON = true; +var USER_LIST_DEBUG_ON = false; function initPage(){ nunjucks.configure({ autoescape: true }); From 0b6bab0003ecf33a263a708ac9af21427f8d9ce2 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 1 Jun 2017 16:02:20 -0400 Subject: [PATCH 12/91] minor tweaks including adding column id, pluralizing the 'displaying: (num) to (num)' message numbers, etc' --- src/main/java/Bundle.properties | 1 + .../harvard/iq/dataverse/UserServiceBean.java | 6 ++++++ .../harvard/iq/dataverse/mydata/Pager.java | 2 ++ .../iq/dataverse/userdata/UserListMaker.java | 3 ++- .../webapp/mydata_templates/pagination.html | 2 +- .../webapp/mydata_templates/user_list.html | 20 ++++++++++--------- .../webapp/resources/js/dashboard_users.js | 2 +- 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index ede12fcc743..49b8ad47364 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1635,6 +1635,7 @@ citationFrame.banner.countdownMessage.seconds=seconds dashboard.card.users.header=Users dashboard.card.users.message=List and manage users. dashboard.card.users.btn.manage=Manage Users +dashboard.list_users.tbl_header.userId=User ID dashboard.list_users.tbl_header.userIdentifier=User name dashboard.list_users.tbl_header.lastName=Last Name dashboard.list_users.tbl_header.firstName=First Name diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 71c001deae9..03f54970a10 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -84,6 +84,9 @@ private String getTimestampStringOrNull(Object dbResult){ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Integer resultLimit, Integer offset) { System.out.println("getUserListAsJSON 1"); + if ((offset == null)||(offset < 0)){ + offset = 0; + } // ------------------------------------------------- // Retrieve a list of user attributes from a native query // ------------------------------------------------- @@ -100,6 +103,8 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int // We have results, format them into a JSON object // ------------------------------------------------- JsonArrayBuilder jsonUserListArray = Json.createArrayBuilder(); + + offset++; // used for the rowNumber for (Object[] result : userResults) { // not putting explicit nulls for now b/c https://stackoverflow.com/questions/22363925/jsr-353-how-to-add-null-values-using-javax-json-jsonobjectbuilder @@ -107,6 +112,7 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int NullSafeJsonBuilder singleUserData = NullSafeJsonBuilder.jsonObjectBuilder(); singleUserData.add("id", (int)result[0]) + .add("rowNum", offset++) .add("userIdentifier", (String)result[1]) .add("lastName", this.getStringOrNull(result[2])) .add("firstName", this.getStringOrNull(result[3])) diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java index 17f804a1b6d..d0458457043 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java @@ -342,6 +342,8 @@ public JsonObjectBuilder asJsonObjectBuilder(){ .add("nextPageNumber", this.nextPageNumber) .add("startCardNumber", this.startCardNumber) .add("endCardNumber", this.endCardNumber) + .add("startCardNumberString", this.addCommasToNumber(this.startCardNumber)) + .add("endCardNumberString", this.addCommasToNumber(this.endCardNumber)) .add("remainingCards", this.remainingCards) .add("numberNextResults", this.numberNextResults); diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index d028d4c9349..8a2e23f350a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -120,7 +120,8 @@ private JsonObjectBuilder getNoResultsJSON(){ public JsonObjectBuilder getBundleStrings(){ - return Json.createObjectBuilder() + return Json.createObjectBuilder() + .add("userId", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userId")) .add("userIdentifier", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userIdentifier")) .add("lastName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastName")) .add("firstName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.firstName")) diff --git a/src/main/webapp/mydata_templates/pagination.html b/src/main/webapp/mydata_templates/pagination.html index 6dbaf85c55a..3e97073afb9 100644 --- a/src/main/webapp/mydata_templates/pagination.html +++ b/src/main/webapp/mydata_templates/pagination.html @@ -14,7 +14,7 @@ {% endif %} {% if endCardNumber > startCardNumber %} -
Displaying: {{ startCardNumber }} to {{ endCardNumber }} +
Displaying: {{ startCardNumberString }} to {{ endCardNumberString }} {% endif %}
diff --git a/src/main/webapp/mydata_templates/user_list.html b/src/main/webapp/mydata_templates/user_list.html index 973568d4743..fd0dd1f0e0e 100644 --- a/src/main/webapp/mydata_templates/user_list.html +++ b/src/main/webapp/mydata_templates/user_list.html @@ -1,27 +1,29 @@ - +
- - - - - - + + + + + + + {% for name_info in data.users -%} - + + {% else %} - + {% endfor %} diff --git a/src/main/webapp/resources/js/dashboard_users.js b/src/main/webapp/resources/js/dashboard_users.js index 900feeba95a..f0a8be4f16d 100644 --- a/src/main/webapp/resources/js/dashboard_users.js +++ b/src/main/webapp/resources/js/dashboard_users.js @@ -1,5 +1,5 @@ -var USER_LIST_DEBUG_ON = true; +var USER_LIST_DEBUG_ON = false; function initPage(){ nunjucks.configure({ autoescape: true }); From 13f7ca57d2d354d13d399b7a6a6cd30a2b8c9a0b Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 5 Jun 2017 11:26:54 -0400 Subject: [PATCH 13/91] #3614 - proof of concept of dropping prime faces table over Raman's custom query --- .../harvard/iq/dataverse/UserServiceBean.java | 20 ++++++++++--------- .../dashboard/DashboardUsersPage.java | 12 +++++++++++ src/main/webapp/dashboard-users.xhtml | 20 ++++++++++++++++++- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 03f54970a10..d4916551d54 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -165,8 +165,7 @@ public List getUserList(String searchTerm, String sortKey, Integer res qstr += " u.affiliation, u.superuser,"; qstr += " u.position, u.modificationtime"; qstr += " FROM authenticateduser u"; - qstr += " WHERE "; - qstr += getSharedSearchClause(); + qstr += getSharedSearchClause(searchTerm); qstr += " ORDER BY u.useridentifier"; qstr += " LIMIT " + resultLimit; qstr += " OFFSET " + offset; @@ -190,12 +189,16 @@ public List getUserList(String searchTerm, String sortKey, Integer res * @param searchTerm * @return */ - private String getSharedSearchClause(){ + private String getSharedSearchClause(String searchTerm){ + if (searchTerm.isEmpty()){ + return ""; + } + - String searchClause = " u.useridentifier ILIKE #searchTerm"; - searchClause += " OR u.firstname ILIKE #searchTerm"; - searchClause += " OR u.lastname ILIKE #searchTerm"; - searchClause += " OR u.email ILIKE #searchTerm"; + String searchClause = "WHERE u.useridentifier LIKE '%" + searchTerm +"%'"; + searchClause += " OR u.firstname LIKE '%" + searchTerm +"%'"; + searchClause += " OR u.lastname LIKE '%" + searchTerm +"%'"; + searchClause += " OR u.email LIKE '%" + searchTerm +"%'"; return searchClause; } @@ -213,8 +216,7 @@ public Long getUserCount(String searchTerm) { String qstr = "SELECT count(u.id)"; qstr += " FROM authenticateduser u"; - qstr += " WHERE "; - qstr += getSharedSearchClause(); + qstr += getSharedSearchClause(searchTerm); qstr += ";"; Query nativeQuery = em.createNativeQuery(qstr); diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index b55ec6977a1..4627b31e340 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -6,6 +6,7 @@ import edu.harvard.iq.dataverse.api.Admin; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import java.util.List; import java.util.logging.Logger; import javax.ejb.EJB; import javax.faces.view.ViewScoped; @@ -18,6 +19,16 @@ public class DashboardUsersPage implements java.io.Serializable { private static final Logger logger = Logger.getLogger(DashboardUsersPage.class.getCanonicalName()); private AuthenticatedUser authUser = null; + + private List userList = null; + + public List getUserList() { + return userService.getUserList("", null, Integer.SIZE, Integer.SIZE); + } + + public void setUserList(List userList) { + this.userList = userList; + } @EJB AuthenticationServiceBean authenticationService; @@ -34,6 +45,7 @@ public String init() { if ((session.getUser() != null) && (session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())) { authUser = (AuthenticatedUser) session.getUser(); + userList = userService.getUserList("", null, Integer.SIZE, Integer.SIZE); } else { return permissionsWrapper.notAuthorized(); // redirect to login OR give some type ‘you must be logged in message' diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 159b14dbaaf..1c1ebb85879 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -53,7 +53,25 @@ }); - + + + + + + + + + + + + + + + + + + + From f6e2371a8b8a7d99a74bd651365e4cdd180ae8d7 Mon Sep 17 00:00:00 2001 From: Derek Murphy Date: Mon, 5 Jun 2017 11:33:55 -0400 Subject: [PATCH 14/91] Updated Guides [ref: #3614] Deleted "Administration" from Installation Guide and moved its contents into new sections in the Admin Guide, where they make more sense. In the process, added documentation of the User List feature. --- doc/sphinx-guides/source/admin/index.rst | 4 + .../source/admin/maintenance.rst | 9 ++ doc/sphinx-guides/source/admin/monitoring.rst | 11 ++ .../source/admin/solr-search-index.rst | 47 ++++++++ .../source/admin/troubleshooting.rst | 15 ++- .../source/admin/user-administration.rst | 39 +++++++ .../source/installation/administration.rst | 103 ------------------ .../source/installation/config.rst | 6 +- .../source/installation/index.rst | 1 - .../source/installation/shibboleth.rst | 2 +- 10 files changed, 127 insertions(+), 110 deletions(-) create mode 100644 doc/sphinx-guides/source/admin/maintenance.rst create mode 100644 doc/sphinx-guides/source/admin/monitoring.rst create mode 100644 doc/sphinx-guides/source/admin/solr-search-index.rst create mode 100644 doc/sphinx-guides/source/admin/user-administration.rst delete mode 100644 doc/sphinx-guides/source/installation/administration.rst diff --git a/doc/sphinx-guides/source/admin/index.rst b/doc/sphinx-guides/source/admin/index.rst index 5224e9e2a19..046bc326813 100755 --- a/doc/sphinx-guides/source/admin/index.rst +++ b/doc/sphinx-guides/source/admin/index.rst @@ -19,4 +19,8 @@ Contents: metadataexport timers geoconnect-worldmap + user-administration + solr-search-index + monitoring + maintenance troubleshooting diff --git a/doc/sphinx-guides/source/admin/maintenance.rst b/doc/sphinx-guides/source/admin/maintenance.rst new file mode 100644 index 00000000000..09eadb097c4 --- /dev/null +++ b/doc/sphinx-guides/source/admin/maintenance.rst @@ -0,0 +1,9 @@ +Maintenance +=========== + +.. contents:: Contents: + :local: + +When you have scheduled down time for your production servers, we provide a :download:`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. \ No newline at end of file diff --git a/doc/sphinx-guides/source/admin/monitoring.rst b/doc/sphinx-guides/source/admin/monitoring.rst new file mode 100644 index 00000000000..5e2eb95abca --- /dev/null +++ b/doc/sphinx-guides/source/admin/monitoring.rst @@ -0,0 +1,11 @@ +Monitoring +=========== + +.. contents:: Contents: + :local: + +In production you'll want to monitor the usual suspects such as CPU, memory, free disk space, etc. + +https://github.com/IQSS/dataverse/issues/2595 contains some information on enabling monitoring of Glassfish, which is disabled by default. + +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. diff --git a/doc/sphinx-guides/source/admin/solr-search-index.rst b/doc/sphinx-guides/source/admin/solr-search-index.rst new file mode 100644 index 00000000000..a599d9c4daa --- /dev/null +++ b/doc/sphinx-guides/source/admin/solr-search-index.rst @@ -0,0 +1,47 @@ +Solr Search Index +================= + +Dataverse requires Solr to be operational at all times. If you stop Solr, you should see a error about this on the home page, which is powered by the search index Solr provides. You can set up Solr by following the steps in our Installation Guide's :doc:`/installation/prerequisites` and :doc:`/installation/config` sections explaining how to configure it. This section you're reading now is about the care and feeding of the search index. PostgreSQL is the "source of truth" and the Dataverse application will copy data from PostgreSQL into Solr. For this reason, the search index can be rebuilt at any time. Depending on the amount of data you have, this can be a slow process. You are encouraged to experiment with production data to get a sense of how long a full reindexing will take. + +.. contents:: Contents: + :local: + +Full Reindex +------------- + +There are two ways to perform a full reindex of the Dataverse search index. Starting with a "clear" ensures a completely clean index but involves downtime. Reindexing in place doesn't involve downtime but does not ensure a completely clean index. + +Clear and Reindex ++++++++++++++++++ + +Clearing Data from Solr +~~~~~~~~~~~~~~~~~~~~~~~ + +Please note that the moment you issue this command, it will appear to end users looking at the home page that all data is gone! This is because the home page is powered by the search index. + +``curl http://localhost:8080/api/admin/index/clear`` + +Start Async Reindex +~~~~~~~~~~~~~~~~~~~ + +Please note that this operation may take hours depending on the amount of data in your system. This known issue is being tracked at https://github.com/IQSS/dataverse/issues/50 + +``curl http://localhost:8080/api/admin/index`` + +Reindex in Place ++++++++++++++++++ + +An alternative to completely clearing the search index is to reindex in place. + +Clear Index Timestamps +~~~~~~~~~~~~~~~~~~~~~~ + +``curl -X DELETE http://localhost:8080/api/admin/index/timestamps`` + +Start or Continue Async Reindex +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If indexing stops, this command should pick up where it left off based on which index timestamps have been set, which is why we start by clearing these timestamps above. These timestamps are stored in the ``dvobject`` database table. + +``curl http://localhost:8080/api/admin/index/continue`` + diff --git a/doc/sphinx-guides/source/admin/troubleshooting.rst b/doc/sphinx-guides/source/admin/troubleshooting.rst index 792d1067c56..fb7ed8a8326 100644 --- a/doc/sphinx-guides/source/admin/troubleshooting.rst +++ b/doc/sphinx-guides/source/admin/troubleshooting.rst @@ -3,10 +3,21 @@ Troubleshooting =============== -.. contents:: :local: - This new (as of v.4.6) section of the Admin guide is for tips on how to diagnose and fix system problems. +.. contents:: Contents: + :local: + +Glassfish +--------- + +``server.log`` is the main place to look when you encounter problems. Hopefully an error message has been logged. If there's a stack trace, it may be of interest to developers, especially they can trace line numbers back to a tagged version. + +For debugging purposes, you may find it helpful to increase logging levels as mentioned in the :doc:`/developers/debugging` section of the Developer Guide. + +Our guides focus on using the command line to manage Glassfish but you might be interested in an admin GUI at http://localhost:4848 + + Deployment fails, "EJB Timer Service not available" --------------------------------------------------- diff --git a/doc/sphinx-guides/source/admin/user-administration.rst b/doc/sphinx-guides/source/admin/user-administration.rst new file mode 100644 index 00000000000..370947547d3 --- /dev/null +++ b/doc/sphinx-guides/source/admin/user-administration.rst @@ -0,0 +1,39 @@ +User Administration +=================== + +This section focuses on user administration tools and tasks. + +.. contents:: Contents: + :local: + +Manage Users Table +------------------ + +The Manage Users table gives the network administrator a list of all user accounts in table form. It lists username, full name, email address, and whether or not the user has Superuser status. + +Usernames are listed alphabetically and clicking on a username takes you to the account page that contains detailed information on that account. + +You can access the Manage Users table by clicking the "Manage Users" button on the Dashboard, which is linked from the header of all Dataverse pages (if you're loggied in as an administrator). + +Confirm Email +------------- + +Dataverse encourages builtin/local users to verify their email address upon signup or email change so that sysadmins can be assured that users can be contacted. + +The app will send a standard welcome email with a URL the user can click, which, when activated, will store a ``lastconfirmed`` timestamp in the ``authenticateduser`` table of the database. Any time this is "null" for a user (immediately after signup and/or changing of their Dataverse email address), their current email on file is considered to not be verified. The link that is sent expires after a time (the default is 24 hours), but this is configurable by a superuser via the ``:MinutesUntilConfirmEmailTokenExpires`` config option. + +Should users' URL token expire, they will see a "Verify Email" button on the account information page to send another URL. + +Sysadmins can determine which users have verified their email addresses by looking for the presence of the value ``emailLastConfirmed`` in the JSON output from listing users (see the "Admin" section of the :doc:`/api/native-api`). As mentioned in the :doc:`/user/account` section of the User Guide, the email addresses for Shibboleth users are re-confirmed on every login. + +Deleting an API Token +--------------------- + +If an API token is compromised it should be deleted. Users can generate a new one for themselves as explained in the :doc:`/user/account` section of the User Guide, but you may want to preemptively delete tokens from the database. + +Using the API token 7ae33670-be21-491d-a244-008149856437 as an example: + +``delete from apitoken where tokenstring = '7ae33670-be21-491d-a244-008149856437';`` + +You should expect the output ``DELETE 1`` after issuing the command above. + diff --git a/doc/sphinx-guides/source/installation/administration.rst b/doc/sphinx-guides/source/installation/administration.rst deleted file mode 100644 index b08b510c434..00000000000 --- a/doc/sphinx-guides/source/installation/administration.rst +++ /dev/null @@ -1,103 +0,0 @@ -Administration -============== - -This section focuses on system and database administration tasks. Please see the :doc:`/user/index` for tasks having to do with having the "Admin" role on a dataverse or dataset. - -.. contents:: :local: - -Solr Search Index ------------------ - -Dataverse requires Solr to be operational at all times. If you stop Solr, you should see a error about this on the home page, which is powered by the search index Solr provides. You set up Solr by following the steps in the :doc:`prerequisites` section and the :doc:`config` section explained how to configure it. This section is about the care and feeding of the search index. PostgreSQL is the "source of truth" and the Dataverse application will copy data from PostgreSQL into Solr. For this reason, the search index can be rebuilt at any time but depending on the amount of data you have, this can be a slow process. You are encouraged to experiment with production data to get a sense of how long a full reindexing will take. - -Full Reindex -++++++++++++ - -There are two ways to perform a full reindex of the Dataverse search index. Starting with a "clear" ensures a completely clean index but involves downtime. Reindexing in place doesn't involve downtime but does not ensure a completely clean index. - -Clear and Reindex -~~~~~~~~~~~~~~~~~ - -Clearing Data from Solr -....................... - -Please note that the moment you issue this command, it will appear to end users looking at the home page that all data is gone! This is because the home page is powered by the search index. - -``curl http://localhost:8080/api/admin/index/clear`` - -Start Async Reindex -................... - -Please note that this operation may take hours depending on the amount of data in your system. This known issue is being tracked at https://github.com/IQSS/dataverse/issues/50 - -``curl http://localhost:8080/api/admin/index`` - -Reindex in Place -~~~~~~~~~~~~~~~~ - -An alternative to completely clearing the search index is to reindex in place. - -Clear Index Timestamps -...................... - -``curl -X DELETE http://localhost:8080/api/admin/index/timestamps`` - -Start or Continue Async Reindex -................................ - -If indexing stops, this command should pick up where it left off based on which index timestamps have been set, which is why we start by clearing these timestamps above. These timestamps are stored in the ``dvobject`` database table. - -``curl http://localhost:8080/api/admin/index/continue`` - -Glassfish ---------- - -``server.log`` is the main place to look when you encounter problems. Hopefully an error message has been logged. If there's a stack trace, it may be of interest to developers, especially they can trace line numbers back to a tagged version. - -For debugging purposes, you may find it helpful to increase logging levels as mentioned in the :doc:`/developers/debugging` section of the Developer Guide. - -This guide has focused on using the command line to manage Glassfish but you might be interested in an admin GUI at http://localhost:4848 - -Monitoring ----------- - -In production you'll want to monitor the usual suspects such as CPU, memory, free disk space, etc. - -https://github.com/IQSS/dataverse/issues/2595 contains some information on enabling monitoring of Glassfish, which is disabled by default. - -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 :download:`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 -------------------- - -There isn't much in the way of user administration tools built in to Dataverse. - -Confirm Email -+++++++++++++ - -Dataverse encourages builtin/local users to verify their email address upon signup or email change so that sysadmins can be assured that users can be contacted. - -The app will send a standard welcome email with a URL the user can click, which, when activated, will store a ``lastconfirmed`` timestamp in the ``authenticateduser`` table of the database. Any time this is "null" for a user (immediately after signup and/or changing of their Dataverse email address), their current email on file is considered to not be verified. The link that is sent expires after a time (the default is 24 hours), but this is configurable by a superuser via the ``:MinutesUntilConfirmEmailTokenExpires`` config option. - -Should users' URL token expire, they will see a "Verify Email" button on the account information page to send another URL. - -Sysadmins can determine which users have verified their email addresses by looking for the presence of the value ``emailLastConfirmed`` in the JSON output from listing users (see the "Admin" section of the :doc:`/api/native-api`). As mentioned in the :doc:`/user/account` section of the User Guide, the email addresses for Shibboleth users are re-confirmed on every login. - -Deleting an API Token -+++++++++++++++++++++ - -If an API token is compromised it should be deleted. Users can generate a new one for themselves as explained in the :doc:`/user/account` section of the User Guide, but you may want to preemptively delete tokens from the database. - -Using the API token 7ae33670-be21-491d-a244-008149856437 as an example: - -``delete from apitoken where tokenstring = '7ae33670-be21-491d-a244-008149856437';`` - -You should expect the output ``DELETE 1`` after issuing the command above. - diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index 368cfaa7c78..ee722845ea7 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -6,7 +6,7 @@ Now that you've successfully logged into Dataverse with a superuser account afte Settings within Dataverse itself are managed via JVM options or by manipulating values in the ``setting`` table directly or through API calls. Configuring Solr requires manipulating XML files. -Once you have finished securing and configuring your Dataverse installation, proceed to the :doc:`administration` section. Advanced configuration topics are covered in the :doc:`r-rapache-tworavens`, :doc:`shibboleth` and :doc:`oauth2` sections. +Once you have finished securing and configuring your Dataverse installation, you may proceed to the :doc:`/admin/index` for more information on the ongoing administration of a Dataverse installation. Advanced configuration topics are covered in the :doc:`r-rapache-tworavens`, :doc:`shibboleth` and :doc:`oauth2` sections. .. contents:: :local: @@ -226,7 +226,7 @@ Congratulations! You've gone live! It's time to announce your new data resposito Administration of Your Dataverse Installation +++++++++++++++++++++++++++++++++++++++++++++ -Now that you're live you'll want to review the :doc:`/admin/index`. Please note that there is also an :doc:`administration` section of this Installation Guide that will be moved to the newer Admin Guide in the future. +Now that you're live you'll want to review the :doc:`/admin/index` for more information about the ongoing administration of a Dataverse installation. JVM Options ----------- @@ -661,7 +661,7 @@ Allow for migration of non-conformant data (especially dates) from DVN 3.x to Da :MinutesUntilConfirmEmailTokenExpires +++++++++++++++++++++++++++++++++++++ -The duration in minutes before "Confirm Email" URLs expire. The default is 1440 minutes (24 hours). See also :doc:`/installation/administration`. +The duration in minutes before "Confirm Email" URLs expire. The default is 1440 minutes (24 hours). See also the :doc:`/admin/user-administration` section of our Admin Guide. :DefaultAuthProvider ++++++++++++++++++++ diff --git a/doc/sphinx-guides/source/installation/index.rst b/doc/sphinx-guides/source/installation/index.rst index 469bb75a481..010177f1d10 100755 --- a/doc/sphinx-guides/source/installation/index.rst +++ b/doc/sphinx-guides/source/installation/index.rst @@ -15,7 +15,6 @@ Contents: prerequisites installation-main config - administration upgrading r-rapache-tworavens geoconnect diff --git a/doc/sphinx-guides/source/installation/shibboleth.rst b/doc/sphinx-guides/source/installation/shibboleth.rst index 49ba9868f19..32e9aff8aec 100644 --- a/doc/sphinx-guides/source/installation/shibboleth.rst +++ b/doc/sphinx-guides/source/installation/shibboleth.rst @@ -348,7 +348,7 @@ If you have more than one Glassfish server, you should use the same ``sp-cert.pe Debugging --------- -The :doc:`administration` section explains how to increase Glassfish logging levels. The relevant classes and packages are: +The :doc:`/admin/troubleshooting` section of the Admin Guide explains how to increase Glassfish logging levels. The relevant classes and packages are: - edu.harvard.iq.dataverse.Shib - edu.harvard.iq.dataverse.authorization.providers.shib From 791a03930c6a15c37a57a59e846ddabf9327a1b2 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 5 Jun 2017 14:59:48 -0400 Subject: [PATCH 15/91] #3614 - converting to non-JSON version.... --- .../harvard/iq/dataverse/UserServiceBean.java | 47 ++++++-- .../dashboard/DashboardUsersPage.java | 113 ++++++++++++++---- .../dataverse/userdata/OffsetPageValues.java | 61 ++++++++++ src/main/webapp/dashboard-users.xhtml | 24 ++-- src/main/webapp/dashboard.xhtml | 4 +- 5 files changed, 197 insertions(+), 52 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index d4916551d54..f9958fa5e11 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -1,12 +1,9 @@ package edu.harvard.iq.dataverse; -import com.google.gson.Gson; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; -import java.math.BigDecimal; import java.sql.Timestamp; -import java.util.HashSet; import java.util.List; import java.util.logging.Logger; import javax.ejb.EJB; @@ -14,8 +11,6 @@ import javax.inject.Named; import javax.json.Json; import javax.json.JsonArrayBuilder; -import javax.json.JsonObjectBuilder; -import javax.json.JsonValue; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; @@ -173,8 +168,8 @@ public List getUserList(String searchTerm, String sortKey, Integer res System.out.println("--------------\n\n" + qstr); - Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", searchTerm + "%"); + Query nativeQuery = em.createNativeQuery(qstr); + nativeQuery.setParameter("searchTerm", "%" + searchTerm + "%"); return nativeQuery.getResultList(); @@ -194,15 +189,47 @@ private String getSharedSearchClause(String searchTerm){ return ""; } - - String searchClause = "WHERE u.useridentifier LIKE '%" + searchTerm +"%'"; + /* + String searchClause = " WHERE u.useridentifier LIKE '%" + searchTerm +"%'"; searchClause += " OR u.firstname LIKE '%" + searchTerm +"%'"; searchClause += " OR u.lastname LIKE '%" + searchTerm +"%'"; searchClause += " OR u.email LIKE '%" + searchTerm +"%'"; + */ + String searchClause = " WHERE u.useridentifier ILIKE #searchTerm"; + searchClause += " OR u.firstname ILIKE #searchTerm"; + searchClause += " OR u.lastname ILIKE #searchTerm"; + searchClause += " OR u.email ILIKE #searchTerm"; return searchClause; } + + /** + * Return the number of superusers -- for the dashboard + * @return + */ + public Long getSuperUserCount() { + + String qstr = "SELECT count(id)"; + qstr += " FROM authenticateduser"; + qstr += " WHERE superuser = true"; + qstr += ";"; + + Query nativeQuery = em.createNativeQuery(qstr); + + return (Long)nativeQuery.getSingleResult(); + + } + + /** + * Return count of all users + * @return + */ + public Long getTotalUserCount(){ + + return getUserCount(null); + } + /** * * @param searchTerm @@ -220,7 +247,7 @@ public Long getUserCount(String searchTerm) { qstr += ";"; Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", searchTerm + "%"); + nativeQuery.setParameter("searchTerm", "%" + searchTerm + "%"); return (Long)nativeQuery.getSingleResult(); diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 4627b31e340..c4e8498c388 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -6,7 +6,12 @@ import edu.harvard.iq.dataverse.api.Admin; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.mydata.Pager; +import edu.harvard.iq.dataverse.userdata.OffsetPageValues; +import edu.harvard.iq.dataverse.userdata.UserListMaker; +import java.text.NumberFormat; import java.util.List; +import java.util.Locale; import java.util.logging.Logger; import javax.ejb.EJB; import javax.faces.view.ViewScoped; @@ -16,36 +21,33 @@ @ViewScoped @Named("DashboardUsersPage") public class DashboardUsersPage implements java.io.Serializable { - - private static final Logger logger = Logger.getLogger(DashboardUsersPage.class.getCanonicalName()); - private AuthenticatedUser authUser = null; - - private List userList = null; - - public List getUserList() { - return userService.getUserList("", null, Integer.SIZE, Integer.SIZE); - } - - public void setUserList(List userList) { - this.userList = userList; - } - + @EJB AuthenticationServiceBean authenticationService; - @EJB UserServiceBean userService; - @Inject DataverseSession session; @Inject PermissionsWrapper permissionsWrapper; + private static final Logger logger = Logger.getLogger(DashboardUsersPage.class.getCanonicalName()); + + private AuthenticatedUser authUser = null; + private Integer selectedPage = 1; + private UserListMaker userListMaker = null; + + private Pager pager; + private List userList; + + public String init() { + System.out.println("_YE_OLDE_QUERY_COUNTER_"); // for debug purposes if ((session.getUser() != null) && (session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())) { authUser = (AuthenticatedUser) session.getUser(); - userList = userService.getUserList("", null, Integer.SIZE, Integer.SIZE); + userListMaker = new UserListMaker(userService); + runUserSearch(); } else { return permissionsWrapper.notAuthorized(); // redirect to login OR give some type ‘you must be logged in message' @@ -53,20 +55,85 @@ public String init() { return null; } + + + public boolean runUserSearch(){ + + String searchTerm = "a"; + + /** + * (1) Determine the number of users returned by the count + */ + Long userCount = userListMaker.getUserCountWithSearch(null); + + int itemsPerPage = UserListMaker.ITEMS_PER_PAGE; + /** + * (2) Based on the page number and number of users, + * determine the off set to use when querying + */ + OffsetPageValues offsetPageValues = userListMaker.getOffset(userCount, getSelectedPage(), itemsPerPage); + + /** + * Update the pageNumber on the page + */ + setSelectedPage(offsetPageValues.getPageNumber()); + int offset = offsetPageValues.getOffset(); + + /** + * (3) Run the search and update the user list + */ + String sortKey = null; + this.userList = userService.getUserList(searchTerm, sortKey, UserListMaker.ITEMS_PER_PAGE, offsetPageValues.getOffset()); + + pager = new Pager(userCount.intValue(), itemsPerPage, getSelectedPage()); + + return true; + } public String getListUsersAPIPath() { //return "ok"; return Admin.listUsersFullAPIPath; } - public long getUserCount() { - String nullSearchTerm = null; - return userService.getUserCount(nullSearchTerm); + /** + * Number of total users + * @return + */ + public String getUserCount() { + //return userService.getTotalUserCount(); + + return NumberFormat.getNumberInstance(Locale.US).format(userService.getTotalUserCount()); } - public long getSuperUserUserCount() { - // FIXME: Return the actual count of superusers. - return 2l; + /** + * Number of total Superusers + * @return + */ + public Long getSuperUserCount() { + + return userService.getSuperUserCount(); } + + public List getUserList() { + return this.userList; + } + + public Pager getPager() { + return this.pager; + } + + private void setSelectedPage(Integer pgNum){ + if ((pgNum == null)||(pgNum < 1)){ + this.selectedPage = 1; + } + selectedPage = pgNum; + } + + public Integer getSelectedPage(){ + if ((selectedPage == null)||(selectedPage < 1)){ + setSelectedPage(null); + } + return selectedPage; + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java b/src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java new file mode 100644 index 00000000000..719546a346c --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java @@ -0,0 +1,61 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.userdata; + +/** + * + * @author rmp553 + */ +public class OffsetPageValues { + + private Integer offset; + private Integer pageNumber; + + + /* + * Constructor + */ + public OffsetPageValues(Integer offset, Integer pageNumber) { + this.pageNumber = pageNumber; + this.offset = offset; + } + + + + /** + * Set offset + * @param offset + */ + public void setOffset(Integer offset){ + this.offset = offset; + } + + /** + * Get for offset + * @return Integer + */ + public Integer getOffset(){ + return this.offset; + } + + + /** + * Set pageNumber + * @param pageNumber + */ + public void setPageNumber(Integer pageNumber){ + this.pageNumber = pageNumber; + } + + /** + * Get for pageNumber + * @return Integer + */ + public Integer getPageNumber(){ + return this.pageNumber; + } + +} diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 1c1ebb85879..194c0190e8c 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -21,18 +21,19 @@ -
- + + +
-
+
@@ -41,18 +42,8 @@
- - - - + @@ -69,9 +60,8 @@ - - - + + diff --git a/src/main/webapp/dashboard.xhtml b/src/main/webapp/dashboard.xhtml index 6d1cb495a6d..764978cf1b1 100644 --- a/src/main/webapp/dashboard.xhtml +++ b/src/main/webapp/dashboard.xhtml @@ -107,11 +107,11 @@

#{bundle['dashboard.card.users.header']}

- +

Users

- +

Super-Users

From d7bd05067844772cbb7e1276d2d15bebfd0363e2 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 5 Jun 2017 15:37:08 -0400 Subject: [PATCH 16/91] more work on #3614' --- .../dashboard/DashboardUsersPage.java | 28 ++++++- .../iq/dataverse/userdata/UserListMaker.java | 79 +++++++++++++++---- src/main/webapp/dashboard-users.xhtml | 38 ++++++--- 3 files changed, 115 insertions(+), 30 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index c4e8498c388..115c0892643 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -45,7 +45,7 @@ public String init() { System.out.println("_YE_OLDE_QUERY_COUNTER_"); // for debug purposes if ((session.getUser() != null) && (session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())) { - authUser = (AuthenticatedUser) session.getUser(); + authUser = (AuthenticatedUser) session.getUser(); userListMaker = new UserListMaker(userService); runUserSearch(); } else { @@ -59,13 +59,15 @@ public String init() { public boolean runUserSearch(){ + msgt("Run the search!"); + String searchTerm = "a"; - /** * (1) Determine the number of users returned by the count */ - Long userCount = userListMaker.getUserCountWithSearch(null); + Long userCount = userListMaker.getUserCountWithSearch(searchTerm); + msgt("userCount: " + userCount); int itemsPerPage = UserListMaker.ITEMS_PER_PAGE; /** * (2) Based on the page number and number of users, @@ -79,14 +81,20 @@ public boolean runUserSearch(){ setSelectedPage(offsetPageValues.getPageNumber()); int offset = offsetPageValues.getOffset(); + msg("offset: " + offset); + /** * (3) Run the search and update the user list */ String sortKey = null; this.userList = userService.getUserList(searchTerm, sortKey, UserListMaker.ITEMS_PER_PAGE, offsetPageValues.getOffset()); + msg("userList size: " + userList.size()); + pager = new Pager(userCount.intValue(), itemsPerPage, getSelectedPage()); - + + msg("pager: " + pager.asJSONString()); + return true; } @@ -136,4 +144,16 @@ public Integer getSelectedPage(){ } return selectedPage; } + + + private void msg(String s){ + System.out.println(s); + } + + private void msgt(String s){ + msg("-------------------------------"); + msg(s); + msg("-------------------------------"); + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index 8a2e23f350a..b3c8885ea05 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -7,13 +7,7 @@ import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.mydata.Pager; -import edu.harvard.iq.dataverse.search.SearchConstants; import edu.harvard.iq.dataverse.util.BundleUtil; -import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; -import java.math.BigDecimal; -import java.text.NumberFormat; -import java.util.List; -import java.util.Locale; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; @@ -30,7 +24,7 @@ public class UserListMaker { public String errorMessage = null; public static final int ITEMS_PER_PAGE = 25; - + public static final int DEFAULT_OFFSET = 0; /* @@ -41,6 +35,36 @@ public UserListMaker(UserServiceBean userService) { this.userService = userService; } + + public Long getTotalUserCount(boolean superusers_only){ + + if (superusers_only){ + return userService.getSuperUserCount(); + }else{ + return userService.getUserCount(null); // send null for the optional search term + } + + } + + + /** + * + * Get user count with search + * + * @param searchTerm + * @return + */ + public Long getUserCountWithSearch(String searchTerm){ + + if (searchTerm == null){ + searchTerm = ""; + }else{ + searchTerm = searchTerm.trim(); + } + + return userService.getUserCount(searchTerm); + } + /* * Run the search */ @@ -79,18 +103,20 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte // (2) Do some calculations here regarding the selected page, offset, etc. // ------------------------------------------------- - int offset = (selectedPage - 1) * itemsPerPage; - if (offset > userCount){ - offset = 0; - selectedPage = 1; - } + OffsetPageValues offsetPageValues = getOffset(userCount, selectedPage, itemsPerPage); + selectedPage = offsetPageValues.getPageNumber(); + int offset = offsetPageValues.getOffset(); + + //int offset = (selectedPage - 1) * itemsPerPage; + //if (offset > userCount){ + // offset = DEFAULT_OFFSET; + // selectedPage = 1; + //} // ------------------------------------------------- // (3) Retrieve the users // ------------------------------------------------- - - JsonArrayBuilder jsonUserListArray = userService.getUserListAsJSON(searchTerm, sortKey, itemsPerPage, offset); if (jsonUserListArray==null){ return getNoResultsJSON(); @@ -109,6 +135,30 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte } + public OffsetPageValues getOffset(Long userCount, Integer selectedPage, Integer itemsPerPage){ + + if (userCount == null){ + return new OffsetPageValues(DEFAULT_OFFSET, 0); + } + + if (itemsPerPage == null){ + itemsPerPage = ITEMS_PER_PAGE; + } + if ((selectedPage == null)||(selectedPage < 1)){ + selectedPage = 1; + } + + int offset = (selectedPage - 1) * itemsPerPage; + if (offset > userCount){ + offset = DEFAULT_OFFSET; + selectedPage = 1; + } + + return new OffsetPageValues(offset, selectedPage); + + } + + private JsonObjectBuilder getNoResultsJSON(){ return Json.createObjectBuilder() @@ -153,4 +203,5 @@ private void msgt(String s){ msg(s); msg("-------------------------------"); } + } diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 194c0190e8c..e3687973382 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -15,6 +15,7 @@ + @@ -45,21 +46,34 @@ - - - + + + - - - + + + - - - + + + - - - + + + + + + + + + + + + + + + + From 88e33ed401a1da6d3e4b90817a70aced2d749a4f Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 5 Jun 2017 17:08:50 -0400 Subject: [PATCH 17/91] #3614 Cleanup Table Headings/Display --- src/main/java/Bundle.properties | 1 + src/main/webapp/dashboard-users.xhtml | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 49b8ad47364..b342bfb1df8 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1640,4 +1640,5 @@ dashboard.list_users.tbl_header.userIdentifier=User name dashboard.list_users.tbl_header.lastName=Last Name dashboard.list_users.tbl_header.firstName=First Name dashboard.list_users.tbl_header.email=Email +dashboard.list_users.tbl_header.affiliation=Affiliation dashboard.list_users.tbl_header.isSuperuser=Is Superuser? diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index e3687973382..2b4e0e905fa 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -46,7 +46,7 @@ - + @@ -63,15 +63,15 @@ - + - - + + - + From 492ae99ba870077da9b91408e2da9f548927161d Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 6 Jun 2017 10:14:21 -0400 Subject: [PATCH 18/91] #3614 wire up search term update --- src/main/java/Bundle.properties | 1 + .../iq/dataverse/dashboard/DashboardUsersPage.java | 14 ++++++++++++-- src/main/webapp/dashboard-users.xhtml | 7 +++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index b342bfb1df8..773089a2db2 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1635,6 +1635,7 @@ citationFrame.banner.countdownMessage.seconds=seconds dashboard.card.users.header=Users dashboard.card.users.message=List and manage users. dashboard.card.users.btn.manage=Manage Users +dashboard.list_users.searchTerm.watermark=Search these users... dashboard.list_users.tbl_header.userId=User ID dashboard.list_users.tbl_header.userIdentifier=User name dashboard.list_users.tbl_header.lastName=Last Name diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 115c0892643..305a28c39bc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -39,7 +39,8 @@ public class DashboardUsersPage implements java.io.Serializable { private Pager pager; private List userList; - + + private String searchTerm; public String init() { System.out.println("_YE_OLDE_QUERY_COUNTER_"); // for debug purposes @@ -61,7 +62,7 @@ public boolean runUserSearch(){ msgt("Run the search!"); - String searchTerm = "a"; + /** * (1) Determine the number of users returned by the count */ @@ -145,6 +146,15 @@ public Integer getSelectedPage(){ return selectedPage; } + public String getSearchTerm() { + return searchTerm; + } + + public void setSearchTerm(String searchTerm) { + this.searchTerm = searchTerm; + } + + private void msg(String s){ System.out.println(s); diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 2b4e0e905fa..5ec29a34e94 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -22,6 +22,13 @@ + + + + + +
From bd294a1cb900ad4d7f54849f6e5c6613dae88b52 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 6 Jun 2017 11:01:47 -0400 Subject: [PATCH 19/91] #3614 fix search formatting --- src/main/webapp/dashboard-users.xhtml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 5ec29a34e94..23d713bbd26 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -17,17 +17,18 @@ + - + - +
@@ -52,7 +53,7 @@ - + @@ -85,5 +86,6 @@ + From c9a8bbf31b9f7ca479ade710f15958ce600f1e3b Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 6 Jun 2017 11:40:06 -0400 Subject: [PATCH 20/91] #3614 Add search button fix formatting --- src/main/webapp/dashboard-users.xhtml | 97 +++++++++++---------------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 23d713bbd26..0216ae58f1b 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -22,68 +22,53 @@ - - - - - - - -
-
- - - - -
-
-
-
-
- -
-
- + +
+
+
+ + + + + + #{bundle['dataverse.search.btn.find']} + +
-
-
- - - - - - - + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - + +
From 0fafd29dfd24abd464b0fddecb8f5cc4a0f67890 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 6 Jun 2017 12:15:02 -0400 Subject: [PATCH 21/91] new object for user info #3614 --- .../harvard/iq/dataverse/UserServiceBean.java | 43 +-- .../harvard/iq/dataverse/mydata/Pager.java | 7 + .../iq/dataverse/userdata/SingleUserView.java | 244 ++++++++++++++++++ .../iq/dataverse/userdata/UserUtil.java | 56 ++++ 4 files changed, 316 insertions(+), 34 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index f9958fa5e11..721163e594b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -2,6 +2,7 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.search.IndexServiceBean; +import edu.harvard.iq.dataverse.userdata.UserUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.sql.Timestamp; import java.util.List; @@ -42,32 +43,6 @@ public AuthenticatedUser save( AuthenticatedUser user ) { } - /** - * Convenience method to format dbResult - * @param dbResult - * @return - */ - private String getStringOrNull(Object dbResult){ - - if (dbResult == null){ - return null; - } - return (String)dbResult; - } - - /** - * Convenience method to format dbResult - * @param dbResult - * @return - */ - private String getTimestampStringOrNull(Object dbResult){ - - if (dbResult == null){ - return null; - } - return ((Timestamp)dbResult).toString(); - } - /** * @@ -109,13 +84,13 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int singleUserData.add("id", (int)result[0]) .add("rowNum", offset++) .add("userIdentifier", (String)result[1]) - .add("lastName", this.getStringOrNull(result[2])) - .add("firstName", this.getStringOrNull(result[3])) - .add("email", this.getStringOrNull(result[4])) - .add("affiliation", this.getStringOrNull(result[5])) + .add("lastName", UserUtil.getStringOrNull(result[2])) + .add("firstName", UserUtil.getStringOrNull(result[3])) + .add("email", UserUtil.getStringOrNull(result[4])) + .add("affiliation", UserUtil.getStringOrNull(result[5])) .add("isSuperuser", (boolean)result[6]) - .add("position", this.getStringOrNull(result[7])) - .add("modificationTime", this.getTimestampStringOrNull(result[8])); + .add("position", UserUtil.getStringOrNull(result[7])) + .add("modificationTime", UserUtil.getTimestampStringOrNull(result[8])); jsonUserListArray.add(singleUserData); } @@ -169,7 +144,7 @@ public List getUserList(String searchTerm, String sortKey, Integer res System.out.println("--------------\n\n" + qstr); Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", "%" + searchTerm + "%"); + nativeQuery.setParameter("searchTerm", searchTerm + "%"); return nativeQuery.getResultList(); @@ -247,7 +222,7 @@ public Long getUserCount(String searchTerm) { qstr += ";"; Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", "%" + searchTerm + "%"); + nativeQuery.setParameter("searchTerm", searchTerm + "%"); return (Long)nativeQuery.getSingleResult(); diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java index d0458457043..f650bb0350c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java @@ -34,6 +34,7 @@ public class Pager { /* inputs */ public int numResults; + public String numResultsString; public int docsPerPage = SearchConstants.NUM_SOLR_DOCS_TO_RETRIEVE; public int selectedPageNumber = 1; @@ -403,6 +404,12 @@ private void makePageNumberList(){ } } + public String getNumResultsString(){ + + return this.addCommasToNumber(numResults); + + } + public static void main(String[] args) throws IOException { Pager pager = new Pager(100, 10, 1); diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java b/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java new file mode 100644 index 00000000000..a6ab4e1fb98 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java @@ -0,0 +1,244 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.userdata; + +import java.sql.Timestamp; +import java.util.List; + +/** + * + * @author rmp553 + */ +public class SingleUserView { + + private Integer rowNum; + + private Integer id; + + private String userIdentifier; + + private String lastName; + + private String firstName; + + private String email; + + private String affiliation; + + private Boolean isSuperuser; + + private String position; + + private Timestamp modificationTime; + + private String roles; + + + + /* + * Constructor + */ + public SingleUserView(Object[] dbRowValues){ + + this.id = (int)dbRowValues[0]; + this.userIdentifier = (String)dbRowValues[1]; + this.lastName = UserUtil.getStringOrNull(dbRowValues[2]); + this.firstName = UserUtil.getStringOrNull(dbRowValues[3]); + this.email = UserUtil.getStringOrNull(dbRowValues[4]); + this.affiliation = UserUtil.getStringOrNull(dbRowValues[5]); + this.isSuperuser = (boolean)dbRowValues[6]; + this.position = UserUtil.getStringOrNull(dbRowValues[7]); + this.modificationTime = UserUtil.getTimestampOrNull(dbRowValues[8]); + + } + + /** + * Set rowNum + * @param rowNum + */ + public void setRowNum(Integer rowNum){ + this.rowNum = rowNum; + } + + /** + * Get for rowNum + * @return Integer + */ + public Integer getRowNum(){ + return this.rowNum; + } + + + /** + * Set id + * @param id + */ + public void setId(Integer id){ + this.id = id; + } + + /** + * Get for id + * @return Integer + */ + public Integer getId(){ + return this.id; + } + + + /** + * Set userIdentifier + * @param userIdentifier + */ + public void setUserIdentifier(String userIdentifier){ + this.userIdentifier = userIdentifier; + } + + /** + * Get for userIdentifier + * @return String + */ + public String getUserIdentifier(){ + return this.userIdentifier; + } + + + /** + * Set lastName + * @param lastName + */ + public void setLastName(String lastName){ + this.lastName = lastName; + } + + /** + * Get for lastName + * @return String + */ + public String getLastName(){ + return this.lastName; + } + + + /** + * Set firstName + * @param firstName + */ + public void setFirstName(String firstName){ + this.firstName = firstName; + } + + /** + * Get for firstName + * @return String + */ + public String getFirstName(){ + return this.firstName; + } + + + /** + * Set email + * @param email + */ + public void setEmail(String email){ + this.email = email; + } + + /** + * Get for email + * @return String + */ + public String getEmail(){ + return this.email; + } + + + /** + * Set affiliation + * @param affiliation + */ + public void setAffiliation(String affiliation){ + this.affiliation = affiliation; + } + + /** + * Get for affiliation + * @return String + */ + public String getAffiliation(){ + return this.affiliation; + } + + + /** + * Set isSuperuser + * @param isSuperuser + */ + public void setIsSuperuser(Boolean isSuperuser){ + this.isSuperuser = isSuperuser; + } + + /** + * Get for isSuperuser + * @return Boolean + */ + public Boolean getIsSuperuser(){ + return this.isSuperuser; + } + + + /** + * Set position + * @param position + */ + public void setPosition(String position){ + this.position = position; + } + + /** + * Get for position + * @return String + */ + public String getPosition(){ + return this.position; + } + + + /** + * Set modificationTime + * @param modificationTime + */ + public void setModificationTime(Timestamp modificationTime){ + this.modificationTime = modificationTime; + } + + /** + * Get for modificationTime + * @return Timestamp + */ + public Timestamp getModificationTime(){ + return this.modificationTime; + } + + + /** + * Set roles + * @param roles + */ + public void setRoles(String roles){ + this.roles = roles; + } + + /** + * Get for roles + * @return String + */ + public String getRoles(){ + return this.roles; + } + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java new file mode 100644 index 00000000000..7cdc2d098d3 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java @@ -0,0 +1,56 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.userdata; + +import java.sql.Timestamp; + +/** + * + * @author rmp553 + */ +public class UserUtil { + + + /** + * Convenience method to format dbResult + * @param dbResult + * @return + */ + public static String getStringOrNull(Object dbResult){ + + if (dbResult == null){ + return null; + } + return (String)dbResult; + } + + /** + * Convenience method to format dbResult + * @param dbResult + * @return + */ + public static String getTimestampStringOrNull(Object dbResult){ + + if (dbResult == null){ + return null; + } + return ((Timestamp)dbResult).toString(); + } + + /** + * Convenience method to format dbResult + * @param dbResult + * @return + */ + public static Timestamp getTimestampOrNull(Object dbResult){ + + if (dbResult == null){ + return null; + } + return (Timestamp)dbResult; + } + +} From 44d1e5fabac01b3738861e556df447464316e765 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 6 Jun 2017 12:27:31 -0400 Subject: [PATCH 22/91] #3614 method to integrate SingleUserView objects --- .../harvard/iq/dataverse/UserServiceBean.java | 38 ++++++++++++++++++- .../iq/dataverse/userdata/SingleUserView.java | 3 +- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 721163e594b..c1785e52fee 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -2,9 +2,11 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.search.IndexServiceBean; +import edu.harvard.iq.dataverse.userdata.SingleUserView; import edu.harvard.iq.dataverse.userdata.UserUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.ejb.EJB; @@ -99,6 +101,40 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int } + public List getUserList(String searchTerm, String sortKey, Integer resultLimit, Integer offset){ + + return getUserListCore(searchTerm, sortKey, resultLimit, offset); + } + + public List getUserListAsSingleUserObjects(String searchTerm, String sortKey, Integer resultLimit, Integer offset){ + + if ((offset == null)||(offset < 0)){ + offset = 0; + } + + List userResults = getUserListCore(searchTerm, sortKey, resultLimit, offset); + + // Initialize empty list for SingleUserView objects + // + List viewObjects = new ArrayList<>(); + + if (userResults == null){ + return viewObjects; + } + + // ------------------------------------------------- + // We have results, format them into SingleUserView objects + // ------------------------------------------------- + int rowNum = offset++; // used for the rowNumber + for (Object[] dbResultRow : userResults) { + rowNum++; + SingleUserView singleUser = new SingleUserView(dbResultRow, rowNum); + viewObjects.add(singleUser); + } + + return viewObjects; + } + /** * @@ -107,7 +143,7 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int * @param resultLimit * @return */ - public List getUserList(String searchTerm, String sortKey, Integer resultLimit, Integer offset) { + private List getUserListCore(String searchTerm, String sortKey, Integer resultLimit, Integer offset) { if ((sortKey == null) || (sortKey.isEmpty())){ sortKey = "u.username"; diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java b/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java index a6ab4e1fb98..e06325b29e4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java @@ -41,7 +41,7 @@ public class SingleUserView { /* * Constructor */ - public SingleUserView(Object[] dbRowValues){ + public SingleUserView(Object[] dbRowValues, Integer rowNum){ this.id = (int)dbRowValues[0]; this.userIdentifier = (String)dbRowValues[1]; @@ -53,6 +53,7 @@ public SingleUserView(Object[] dbRowValues){ this.position = UserUtil.getStringOrNull(dbRowValues[7]); this.modificationTime = UserUtil.getTimestampOrNull(dbRowValues[8]); + this.rowNum = rowNum; } /** From f330552a423676ebaf24c9932b8216a614dfa28b Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 6 Jun 2017 12:31:24 -0400 Subject: [PATCH 23/91] add method so setParameter doesn't differ between count/retrieve queries #3614 --- .../edu/harvard/iq/dataverse/UserServiceBean.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index c1785e52fee..315caa6237a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -180,7 +180,7 @@ private List getUserListCore(String searchTerm, String sortKey, Intege System.out.println("--------------\n\n" + qstr); Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", searchTerm + "%"); + nativeQuery.setParameter("searchTerm", formatSearchTerm(searchTerm)); return nativeQuery.getResultList(); @@ -241,6 +241,17 @@ public Long getTotalUserCount(){ return getUserCount(null); } + private String formatSearchTerm(String searchTerm){ + + if (searchTerm == null){ + return ""; + } + + return searchTerm + "%"; // for LIKE query on right side + + //return "%" + searchTerm + "%"; // for LIKE query on both sides + } + /** * * @param searchTerm @@ -258,7 +269,7 @@ public Long getUserCount(String searchTerm) { qstr += ";"; Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", searchTerm + "%"); + nativeQuery.setParameter("searchTerm", formatSearchTerm(searchTerm)); return (Long)nativeQuery.getSingleResult(); From f4e6b54b76417b9adddf6d663af3657060623761 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 6 Jun 2017 12:40:52 -0400 Subject: [PATCH 24/91] #3614 subsitute SingleUserView object for array --- src/main/java/Bundle.properties | 2 ++ .../harvard/iq/dataverse/UserServiceBean.java | 18 +++++++++++++++ .../dashboard/DashboardUsersPage.java | 7 +++--- src/main/webapp/dashboard-users.xhtml | 22 +++++++++++-------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 773089a2db2..826e94d9d7e 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1636,6 +1636,8 @@ dashboard.card.users.header=Users dashboard.card.users.message=List and manage users. dashboard.card.users.btn.manage=Manage Users dashboard.list_users.searchTerm.watermark=Search these users... + +dashboard.list_users.tbl_header.rowNumber=# dashboard.list_users.tbl_header.userId=User ID dashboard.list_users.tbl_header.userIdentifier=User name dashboard.list_users.tbl_header.lastName=Last Name diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 315caa6237a..327a7998a80 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -101,11 +101,29 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int } + /** + * Return the user information as a List of Arrays--e.g. straight from the db query + * + * @param searchTerm + * @param sortKey + * @param resultLimit + * @param offset + * @return + */ public List getUserList(String searchTerm, String sortKey, Integer resultLimit, Integer offset){ return getUserListCore(searchTerm, sortKey, resultLimit, offset); } + /** + * Return the user information as a List of SingleUserView objects -- easier to work with in the UI + * + * @param searchTerm + * @param sortKey + * @param resultLimit + * @param offset + * @return + */ public List getUserListAsSingleUserObjects(String searchTerm, String sortKey, Integer resultLimit, Integer offset){ if ((offset == null)||(offset < 0)){ diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 305a28c39bc..5852ba0d455 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -8,6 +8,7 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.mydata.Pager; import edu.harvard.iq.dataverse.userdata.OffsetPageValues; +import edu.harvard.iq.dataverse.userdata.SingleUserView; import edu.harvard.iq.dataverse.userdata.UserListMaker; import java.text.NumberFormat; import java.util.List; @@ -38,7 +39,7 @@ public class DashboardUsersPage implements java.io.Serializable { private UserListMaker userListMaker = null; private Pager pager; - private List userList; + private List userList; private String searchTerm; @@ -88,7 +89,7 @@ public boolean runUserSearch(){ * (3) Run the search and update the user list */ String sortKey = null; - this.userList = userService.getUserList(searchTerm, sortKey, UserListMaker.ITEMS_PER_PAGE, offsetPageValues.getOffset()); + this.userList = userService.getUserListAsSingleUserObjects(searchTerm, sortKey, UserListMaker.ITEMS_PER_PAGE, offsetPageValues.getOffset()); msg("userList size: " + userList.size()); @@ -124,7 +125,7 @@ public Long getSuperUserCount() { } - public List getUserList() { + public List getUserList() { return this.userList; } diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 0216ae58f1b..15f521805b0 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -39,32 +39,36 @@
- - - + + + - + - + - + - + + + + + - + - + From a912dcf1dcd99405ff67c7b8d9bc013432181b05 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 6 Jun 2017 12:44:47 -0400 Subject: [PATCH 25/91] comment for #3614 --- src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 327a7998a80..586c7ae2cf2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -181,8 +181,8 @@ private List getUserListCore(String searchTerm, String sortKey, Intege offset = 0; } - - System.out.println("Search key: " + searchTerm); + + // NOTE: IF YOU CHANGE THIS QUERY, THEN CHANGE: SingleUserView.java String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; From c562bd241312e77a5e3ef12a616f08eb6b866a6f Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Tue, 6 Jun 2017 15:07:37 -0400 Subject: [PATCH 26/91] #3614 Add Roles to user table --- src/main/java/Bundle.properties | 1 + .../harvard/iq/dataverse/UserServiceBean.java | 31 ++++++++++++++++++- .../iq/dataverse/userdata/SingleUserView.java | 3 +- src/main/webapp/dashboard-users.xhtml | 4 +++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 826e94d9d7e..094208c8448 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1644,4 +1644,5 @@ dashboard.list_users.tbl_header.lastName=Last Name dashboard.list_users.tbl_header.firstName=First Name dashboard.list_users.tbl_header.email=Email dashboard.list_users.tbl_header.affiliation=Affiliation +dashboard.list_users.tbl_header.roles=Roles dashboard.list_users.tbl_header.isSuperuser=Is Superuser? diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 586c7ae2cf2..7c5cc9352b2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -146,13 +146,42 @@ public List getUserListAsSingleUserObjects(String searchTerm, St int rowNum = offset++; // used for the rowNumber for (Object[] dbResultRow : userResults) { rowNum++; - SingleUserView singleUser = new SingleUserView(dbResultRow, rowNum); + String roles = getUserRolesAsString((Integer) dbResultRow[0]); + SingleUserView singleUser = new SingleUserView(dbResultRow, roles, rowNum); viewObjects.add(singleUser); } return viewObjects; } + + private String getUserRolesAsString(Integer userId) { + String retval = ""; + String userIdentifier = ""; + String qstr = "select useridentifier "; + qstr += " FROM authenticateduser"; + qstr += " WHERE id = " + userId.toString(); + qstr += ";"; + + Query nativeQuery = em.createNativeQuery(qstr); + + userIdentifier = '@' + (String) nativeQuery.getSingleResult(); + qstr = " select distinct d.name from roleassignment a, dataverserole d"; + qstr += " where d.id = a.role_id and a.assigneeidentifier='" + userIdentifier + "'" + + " Order by d.name;"; + + nativeQuery = em.createNativeQuery(qstr); + + List roleList = nativeQuery.getResultList(); + + for (Object o : roleList) { + if (!retval.isEmpty()) { + retval += ", "; + } + retval += (String) o; + } + return retval; + } /** * diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java b/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java index e06325b29e4..75c956d3852 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java @@ -41,7 +41,7 @@ public class SingleUserView { /* * Constructor */ - public SingleUserView(Object[] dbRowValues, Integer rowNum){ + public SingleUserView(Object[] dbRowValues, String roles, Integer rowNum){ this.id = (int)dbRowValues[0]; this.userIdentifier = (String)dbRowValues[1]; @@ -52,6 +52,7 @@ public SingleUserView(Object[] dbRowValues, Integer rowNum){ this.isSuperuser = (boolean)dbRowValues[6]; this.position = UserUtil.getStringOrNull(dbRowValues[7]); this.modificationTime = UserUtil.getTimestampOrNull(dbRowValues[8]); + this.roles = roles; this.rowNum = rowNum; } diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 15f521805b0..1d29d1a0a11 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -66,6 +66,10 @@ + + + + From 554565d0eee6cd81e09def31b624e69d1a10f433 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 6 Jun 2017 16:51:40 -0400 Subject: [PATCH 27/91] #3614 pager info. needs to be linked to selected page --- .../dashboard/DashboardUsersPage.java | 6 ++++ .../harvard/iq/dataverse/mydata/Pager.java | 12 ++++++++ src/main/webapp/dashboard-users.xhtml | 7 +++++ .../webapp/mydata_templates/user_list.html | 30 +++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 5852ba0d455..00fa7b4883a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -129,6 +129,12 @@ public List getUserList() { return this.userList; } + /** + * Pager for when user list exceeds the number of display rows + * (default: UserListMaker.ITEMS_PER_PAGE) + * + * @return + */ public Pager getPager() { return this.pager; } diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java index f650bb0350c..c29f9655c68 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java @@ -14,6 +14,7 @@ import java.net.URLClassLoader; import java.text.NumberFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Locale; import javax.json.Json; @@ -229,6 +230,17 @@ public int[] getPageNumberList(){ return this.pageNumberList; } + public Integer[] getPageListAsIntegerList(){ + + if (pageNumberList == null){ + return null; + } + + // source: https://stackoverflow.com/questions/880581/how-to-convert-int-to-integer-in-java + return Arrays.stream(pageNumberList).boxed().toArray( Integer[]::new ); + + + } /** * @param pageNumberList diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 1d29d1a0a11..6ffa104d453 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -26,6 +26,7 @@
+ @@ -38,6 +39,7 @@
+ @@ -76,6 +78,11 @@ + + + + + diff --git a/src/main/webapp/mydata_templates/user_list.html b/src/main/webapp/mydata_templates/user_list.html index fd0dd1f0e0e..6bb25e3147a 100644 --- a/src/main/webapp/mydata_templates/user_list.html +++ b/src/main/webapp/mydata_templates/user_list.html @@ -1,3 +1,33 @@ +String getCitation(){ + > Backing bean + > get Dataset + to JSON -> Lots of RestAssuredTEsts + to DatasetJSONMap + + JSON Excel Metadata + { + numRows: + } + + + Utility: + > getDatasetCard(DatasetJSONMap){ + return DatasetJSONMap + template = HTML String + } + + + > getCitation(DatasetJSONMap){ + return DatasetJSONMap + template = HTML String + } + getJSONSchema(DatasetJSONMap){ + return DatasetJSONMap + template = HTML String + } + getDublinCoreMetaHTML(DatasetJSONMap){ + return DatasetJSONMap + template = HTML String + } + datasetJSONMap +} +
 {{ data.bundleStrings.userIdentifier }}{{ data.bundleStrings.lastName }}{{ data.bundleStrings.firstName }}{{ data.bundleStrings.email }}{{ data.bundleStrings.isSuperuser }}#{{ data.bundleStrings.userIdentifier }}{{ data.bundleStrings.lastName }}{{ data.bundleStrings.firstName }}{{ data.bundleStrings.email }}{{ data.bundleStrings.userId }}{{ data.bundleStrings.isSuperuser }}
{{ loop.index }}{{ name_info.rowNum }} {{ name_info.userIdentifier }} {{ name_info.lastName }} {{ name_info.firstName }} {{ name_info.email }}{{ name_info.id }} {{ name_info.isSuperuser }}
Sorry. No users found.
Sorry. No users found.
From abde32d1cb03d5a3246c916914338b0866a7d3fe Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Wed, 7 Jun 2017 10:39:01 -0400 Subject: [PATCH 28/91] page .xhtml (should have been added to earlier commit #3614 --- src/main/webapp/dashboard-users-pager.xhtml | 71 +++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/main/webapp/dashboard-users-pager.xhtml diff --git a/src/main/webapp/dashboard-users-pager.xhtml b/src/main/webapp/dashboard-users-pager.xhtml new file mode 100644 index 00000000000..4e7f07d25f3 --- /dev/null +++ b/src/main/webapp/dashboard-users-pager.xhtml @@ -0,0 +1,71 @@ + + + + + +
+ +
+
+ + Found: #{listPager.numResultsString} results + + + Found: #{listPager.numResultsString} result + + + +
Displaying: #{listPager.startCardNumber} to #{listPager.endCardNumber} +
+
+
+ +
+ + + + page count: #{listPager.pageCount}
+ +
+
+
+
+
\ No newline at end of file From 20386bb45bb4c2ecab27336cbbf94ea16a212891 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 7 Jun 2017 11:06:01 -0400 Subject: [PATCH 29/91] #3614 Add Transient Fields to Auth User for display --- .../harvard/iq/dataverse/UserServiceBean.java | 53 ++++++++++++------- .../users/AuthenticatedUser.java | 27 ++++++++++ .../dashboard/DashboardUsersPage.java | 7 ++- .../harvard/iq/dataverse/mydata/Pager.java | 9 ++-- src/main/webapp/dashboard-users.xhtml | 2 +- 5 files changed, 71 insertions(+), 27 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 7c5cc9352b2..74304eec9aa 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -116,15 +116,15 @@ public List getUserList(String searchTerm, String sortKey, Integer res } /** - * Return the user information as a List of SingleUserView objects -- easier to work with in the UI - * + * Return the user information as a List of AuthenticatedUser objects -- easier to work with in the UI + * - With Role added as a transient field * @param searchTerm * @param sortKey * @param resultLimit * @param offset * @return */ - public List getUserListAsSingleUserObjects(String searchTerm, String sortKey, Integer resultLimit, Integer offset){ + public List getAuthenticatedUserList(String searchTerm, String sortKey, Integer resultLimit, Integer offset){ if ((offset == null)||(offset < 0)){ offset = 0; @@ -132,28 +132,44 @@ public List getUserListAsSingleUserObjects(String searchTerm, St List userResults = getUserListCore(searchTerm, sortKey, resultLimit, offset); - // Initialize empty list for SingleUserView objects + // Initialize empty list for AuthenticatedUser objects // - List viewObjects = new ArrayList<>(); + List viewObjects = new ArrayList<>(); if (userResults == null){ return viewObjects; } // ------------------------------------------------- - // We have results, format them into SingleUserView objects + // We have results, format them into AuthenticatedUser objects // ------------------------------------------------- int rowNum = offset++; // used for the rowNumber for (Object[] dbResultRow : userResults) { rowNum++; String roles = getUserRolesAsString((Integer) dbResultRow[0]); - SingleUserView singleUser = new SingleUserView(dbResultRow, roles, rowNum); + AuthenticatedUser singleUser = createAuthenticatedUserForView(dbResultRow, roles, rowNum); viewObjects.add(singleUser); } return viewObjects; } + private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, String roles, int rowNum){ + AuthenticatedUser user = new AuthenticatedUser(); + user.setRowNum(rowNum); + user.setId(new Long((Integer)dbRowValues[0])); + user.setUserIdentifier((String)dbRowValues[1]); + user.setLastName(UserUtil.getStringOrNull(dbRowValues[2])); + user.setFirstName(UserUtil.getStringOrNull(dbRowValues[3])); + user.setEmail(UserUtil.getStringOrNull(dbRowValues[4])); + user.setAffiliation(UserUtil.getStringOrNull(dbRowValues[5])); + user.setSuperuser((Boolean)(dbRowValues[6])); + user.setPosition(UserUtil.getStringOrNull(dbRowValues[7])); + user.setModificationTime(UserUtil.getTimestampOrNull(dbRowValues[8])); + user.setRoles(roles); + return user; + } + private String getUserRolesAsString(Integer userId) { String retval = ""; String userIdentifier = ""; @@ -210,8 +226,7 @@ private List getUserListCore(String searchTerm, String sortKey, Intege offset = 0; } - - // NOTE: IF YOU CHANGE THIS QUERY, THEN CHANGE: SingleUserView.java + //Results of thius query are used to build Authenticated User records String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; @@ -227,7 +242,7 @@ private List getUserListCore(String searchTerm, String sortKey, Intege System.out.println("--------------\n\n" + qstr); Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", formatSearchTerm(searchTerm)); + //nativeQuery.setParameter("searchTerm", formatSearchTerm(searchTerm)); return nativeQuery.getResultList(); @@ -247,17 +262,17 @@ private String getSharedSearchClause(String searchTerm){ return ""; } - /* + String searchClause = " WHERE u.useridentifier LIKE '%" + searchTerm +"%'"; - searchClause += " OR u.firstname LIKE '%" + searchTerm +"%'"; - searchClause += " OR u.lastname LIKE '%" + searchTerm +"%'"; - searchClause += " OR u.email LIKE '%" + searchTerm +"%'"; + searchClause += " OR u.firstname ILIKE '%" + searchTerm +"%'"; + searchClause += " OR u.lastname ILIKE '%" + searchTerm +"%'"; + searchClause += " OR u.email ILIKE '%" + searchTerm +"%'"; + /* + String searchClause = " WHERE u.useridentifier ILIKE :searchTerm"; + searchClause += " OR u.firstname ILIKE :searchTerm"; + searchClause += " OR u.lastname ILIKE :searchTerm"; + searchClause += " OR u.email ILIKE :searchTerm"; */ - String searchClause = " WHERE u.useridentifier ILIKE #searchTerm"; - searchClause += " OR u.firstname ILIKE #searchTerm"; - searchClause += " OR u.lastname ILIKE #searchTerm"; - searchClause += " OR u.email ILIKE #searchTerm"; - return searchClause; } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index e70916a020a..eed7d7fd005 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -132,6 +132,33 @@ public void applyDisplayInfo( AuthenticatedUserDisplayInfo inf ) { setPosition( inf.getPosition()); } } + + + //For User List Admin dashboard + @Transient + private String roles; + + public String getRoles() { + return roles; + } + + public void setRoles(String roles) { + this.roles = roles; + } + + //For User List Admin dashboard + @Transient + private Integer rowNum; + + public Integer getRowNum() { + return rowNum; + } + + public void setRowNum(Integer rowNum) { + this.rowNum = rowNum; + } + + @Override public boolean isAuthenticated() { return true; } diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 00fa7b4883a..6193a9b8f2b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -39,7 +39,7 @@ public class DashboardUsersPage implements java.io.Serializable { private UserListMaker userListMaker = null; private Pager pager; - private List userList; + private List userList; private String searchTerm; @@ -89,7 +89,7 @@ public boolean runUserSearch(){ * (3) Run the search and update the user list */ String sortKey = null; - this.userList = userService.getUserListAsSingleUserObjects(searchTerm, sortKey, UserListMaker.ITEMS_PER_PAGE, offsetPageValues.getOffset()); + this.userList = userService.getAuthenticatedUserList(searchTerm, sortKey, UserListMaker.ITEMS_PER_PAGE, offsetPageValues.getOffset()); msg("userList size: " + userList.size()); @@ -124,8 +124,7 @@ public Long getSuperUserCount() { return userService.getSuperUserCount(); } - - public List getUserList() { + public List getUserList() { return this.userList; } diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java index c29f9655c68..5e7c1d16e6d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java @@ -364,10 +364,13 @@ public JsonObjectBuilder asJsonObjectBuilder(){ // pageNumberList // -------------------- JsonArrayBuilder jsonPageNumberArrayBuilder = Json.createArrayBuilder(); - for (int pg : this.pageNumberList){ - jsonPageNumberArrayBuilder.add(pg); + if (this.pageNumberList != null) { + for (int pg : this.pageNumberList) { + jsonPageNumberArrayBuilder.add(pg); + } + jsonPageInfo.add("pageNumberList", jsonPageNumberArrayBuilder); } - jsonPageInfo.add("pageNumberList", jsonPageNumberArrayBuilder); + // -------------------- return jsonPageInfo; diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 6ffa104d453..483805666dd 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -74,7 +74,7 @@ - + From a81e657b0ef72c0caff09735b4ff6060e108f022 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 7 Jun 2017 11:34:02 -0400 Subject: [PATCH 30/91] #3614 - Remove Single User View --- .../harvard/iq/dataverse/UserServiceBean.java | 1 - .../dashboard/DashboardUsersPage.java | 1 - .../iq/dataverse/userdata/SingleUserView.java | 246 ------------------ 3 files changed, 248 deletions(-) delete mode 100644 src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 74304eec9aa..a4e9c2ce419 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -2,7 +2,6 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.search.IndexServiceBean; -import edu.harvard.iq.dataverse.userdata.SingleUserView; import edu.harvard.iq.dataverse.userdata.UserUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.sql.Timestamp; diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 6193a9b8f2b..4d866bd1ce5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -8,7 +8,6 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.mydata.Pager; import edu.harvard.iq.dataverse.userdata.OffsetPageValues; -import edu.harvard.iq.dataverse.userdata.SingleUserView; import edu.harvard.iq.dataverse.userdata.UserListMaker; import java.text.NumberFormat; import java.util.List; diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java b/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java deleted file mode 100644 index 75c956d3852..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/SingleUserView.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse.userdata; - -import java.sql.Timestamp; -import java.util.List; - -/** - * - * @author rmp553 - */ -public class SingleUserView { - - private Integer rowNum; - - private Integer id; - - private String userIdentifier; - - private String lastName; - - private String firstName; - - private String email; - - private String affiliation; - - private Boolean isSuperuser; - - private String position; - - private Timestamp modificationTime; - - private String roles; - - - - /* - * Constructor - */ - public SingleUserView(Object[] dbRowValues, String roles, Integer rowNum){ - - this.id = (int)dbRowValues[0]; - this.userIdentifier = (String)dbRowValues[1]; - this.lastName = UserUtil.getStringOrNull(dbRowValues[2]); - this.firstName = UserUtil.getStringOrNull(dbRowValues[3]); - this.email = UserUtil.getStringOrNull(dbRowValues[4]); - this.affiliation = UserUtil.getStringOrNull(dbRowValues[5]); - this.isSuperuser = (boolean)dbRowValues[6]; - this.position = UserUtil.getStringOrNull(dbRowValues[7]); - this.modificationTime = UserUtil.getTimestampOrNull(dbRowValues[8]); - this.roles = roles; - - this.rowNum = rowNum; - } - - /** - * Set rowNum - * @param rowNum - */ - public void setRowNum(Integer rowNum){ - this.rowNum = rowNum; - } - - /** - * Get for rowNum - * @return Integer - */ - public Integer getRowNum(){ - return this.rowNum; - } - - - /** - * Set id - * @param id - */ - public void setId(Integer id){ - this.id = id; - } - - /** - * Get for id - * @return Integer - */ - public Integer getId(){ - return this.id; - } - - - /** - * Set userIdentifier - * @param userIdentifier - */ - public void setUserIdentifier(String userIdentifier){ - this.userIdentifier = userIdentifier; - } - - /** - * Get for userIdentifier - * @return String - */ - public String getUserIdentifier(){ - return this.userIdentifier; - } - - - /** - * Set lastName - * @param lastName - */ - public void setLastName(String lastName){ - this.lastName = lastName; - } - - /** - * Get for lastName - * @return String - */ - public String getLastName(){ - return this.lastName; - } - - - /** - * Set firstName - * @param firstName - */ - public void setFirstName(String firstName){ - this.firstName = firstName; - } - - /** - * Get for firstName - * @return String - */ - public String getFirstName(){ - return this.firstName; - } - - - /** - * Set email - * @param email - */ - public void setEmail(String email){ - this.email = email; - } - - /** - * Get for email - * @return String - */ - public String getEmail(){ - return this.email; - } - - - /** - * Set affiliation - * @param affiliation - */ - public void setAffiliation(String affiliation){ - this.affiliation = affiliation; - } - - /** - * Get for affiliation - * @return String - */ - public String getAffiliation(){ - return this.affiliation; - } - - - /** - * Set isSuperuser - * @param isSuperuser - */ - public void setIsSuperuser(Boolean isSuperuser){ - this.isSuperuser = isSuperuser; - } - - /** - * Get for isSuperuser - * @return Boolean - */ - public Boolean getIsSuperuser(){ - return this.isSuperuser; - } - - - /** - * Set position - * @param position - */ - public void setPosition(String position){ - this.position = position; - } - - /** - * Get for position - * @return String - */ - public String getPosition(){ - return this.position; - } - - - /** - * Set modificationTime - * @param modificationTime - */ - public void setModificationTime(Timestamp modificationTime){ - this.modificationTime = modificationTime; - } - - /** - * Get for modificationTime - * @return Timestamp - */ - public Timestamp getModificationTime(){ - return this.modificationTime; - } - - - /** - * Set roles - * @param roles - */ - public void setRoles(String roles){ - this.roles = roles; - } - - /** - * Get for roles - * @return String - */ - public String getRoles(){ - return this.roles; - } - -} From 2de92ea8105966393bc757928d7447ad2e66eaba Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Wed, 7 Jun 2017 12:53:47 -0400 Subject: [PATCH 31/91] #3614 working page' --- .../dashboard/DashboardUsersPage.java | 34 ++++++++++++- src/main/webapp/dashboard-users-pager.xhtml | 51 +++++++++++++++---- src/main/webapp/dashboard-users.xhtml | 9 ++-- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 4d866bd1ce5..18a3a2334dc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -57,6 +57,12 @@ public String init() { return null; } + public boolean runUserSearchWithPage(Integer pageNumber){ + System.err.println("runUserSearchWithPage"); + setSelectedPage(pageNumber); + runUserSearch(); + return true; + } public boolean runUserSearch(){ @@ -92,13 +98,39 @@ public boolean runUserSearch(){ msg("userList size: " + userList.size()); - pager = new Pager(userCount.intValue(), itemsPerPage, getSelectedPage()); + makeNewPager(userCount.intValue(), itemsPerPage, getSelectedPage()); msg("pager: " + pager.asJSONString()); return true; } + /** + * Make sure there is a pager--even if the user count is 0 + * + * @param userCount + * @param displayItemsPerPage + * @param chosenPage + * @return + */ + private boolean makeNewPager(Integer userCount, Integer displayItemsPerPage, Integer chosenPage){ + + if (userCount == null){ + userCount = 0; + } + if (chosenPage == null){ + chosenPage = 1; + } + if (displayItemsPerPage == null){ + displayItemsPerPage = UserListMaker.ITEMS_PER_PAGE; + } + + pager = new Pager(userCount, displayItemsPerPage, chosenPage); + + return true; + } + + public String getListUsersAPIPath() { //return "ok"; return Admin.listUsersFullAPIPath; diff --git a/src/main/webapp/dashboard-users-pager.xhtml b/src/main/webapp/dashboard-users-pager.xhtml index 4e7f07d25f3..05e32b3faff 100644 --- a/src/main/webapp/dashboard-users-pager.xhtml +++ b/src/main/webapp/dashboard-users-pager.xhtml @@ -27,43 +27,72 @@
- + +   + + -
diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 483805666dd..21191a9e365 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -40,6 +40,10 @@ + + + + @@ -79,10 +83,7 @@ - - - - + From 27194440f5965cb8fb266a93b380accf508e8015 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Wed, 7 Jun 2017 14:11:27 -0400 Subject: [PATCH 32/91] #3614 Cleanup user search query code --- .../harvard/iq/dataverse/UserServiceBean.java | 31 ++----------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index a4e9c2ce419..0cae8710a78 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -4,7 +4,6 @@ import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.userdata.UserUtil; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; -import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; @@ -53,7 +52,6 @@ public AuthenticatedUser save( AuthenticatedUser user ) { * @return */ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Integer resultLimit, Integer offset) { - System.out.println("getUserListAsJSON 1"); if ((offset == null)||(offset < 0)){ offset = 0; @@ -238,12 +236,8 @@ private List getUserListCore(String searchTerm, String sortKey, Intege qstr += " OFFSET " + offset; qstr += ";"; - System.out.println("--------------\n\n" + qstr); - - Query nativeQuery = em.createNativeQuery(qstr); - //nativeQuery.setParameter("searchTerm", formatSearchTerm(searchTerm)); - - + Query nativeQuery = em.createNativeQuery(qstr); + return nativeQuery.getResultList(); } @@ -260,18 +254,11 @@ private String getSharedSearchClause(String searchTerm){ if (searchTerm.isEmpty()){ return ""; } - - + String searchClause = " WHERE u.useridentifier LIKE '%" + searchTerm +"%'"; searchClause += " OR u.firstname ILIKE '%" + searchTerm +"%'"; searchClause += " OR u.lastname ILIKE '%" + searchTerm +"%'"; searchClause += " OR u.email ILIKE '%" + searchTerm +"%'"; - /* - String searchClause = " WHERE u.useridentifier ILIKE :searchTerm"; - searchClause += " OR u.firstname ILIKE :searchTerm"; - searchClause += " OR u.lastname ILIKE :searchTerm"; - searchClause += " OR u.email ILIKE :searchTerm"; - */ return searchClause; } @@ -301,17 +288,6 @@ public Long getTotalUserCount(){ return getUserCount(null); } - - private String formatSearchTerm(String searchTerm){ - - if (searchTerm == null){ - return ""; - } - - return searchTerm + "%"; // for LIKE query on right side - - //return "%" + searchTerm + "%"; // for LIKE query on both sides - } /** * @@ -330,7 +306,6 @@ public Long getUserCount(String searchTerm) { qstr += ";"; Query nativeQuery = em.createNativeQuery(qstr); - nativeQuery.setParameter("searchTerm", formatSearchTerm(searchTerm)); return (Long)nativeQuery.getSingleResult(); From 656e60b235f9ebcb3e60e58d13edde9c45ec9b57 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Wed, 7 Jun 2017 14:40:43 -0400 Subject: [PATCH 33/91] #3614 - add built-in user info to query --- .../harvard/iq/dataverse/UserServiceBean.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index a4e9c2ce419..f878659070a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -91,7 +91,10 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int .add("affiliation", UserUtil.getStringOrNull(result[5])) .add("isSuperuser", (boolean)result[6]) .add("position", UserUtil.getStringOrNull(result[7])) - .add("modificationTime", UserUtil.getTimestampStringOrNull(result[8])); + .add("modificationTime", UserUtil.getTimestampStringOrNull(result[8])) + .add("authProviderId", UserUtil.getStringOrNull(result[9])) + .add("authFactoryAlias", UserUtil.getStringOrNull(result[10])); + jsonUserListArray.add(singleUserData); } @@ -230,8 +233,11 @@ private List getUserListCore(String searchTerm, String sortKey, Intege String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; qstr += " u.affiliation, u.superuser,"; - qstr += " u.position, u.modificationtime"; - qstr += " FROM authenticateduser u"; + qstr += " u.position, u.modificationtime,"; + qstr += " prov.id, prov.factoryalias"; + qstr += " FROM authenticateduser u,"; + qstr += " authenticateduserlookup prov_lookup,"; + qstr += " authenticationproviderrow prov"; qstr += getSharedSearchClause(searchTerm); qstr += " ORDER BY u.useridentifier"; qstr += " LIMIT " + resultLimit; @@ -262,7 +268,10 @@ private String getSharedSearchClause(String searchTerm){ } - String searchClause = " WHERE u.useridentifier LIKE '%" + searchTerm +"%'"; + String searchClause = " WHERE"; + searchClause += " u.id = prov_lookup.authenticateduser_id"; + searchClause += " prov_lookup.authenticationproviderid = prov.id"; + searchClause += " u.useridentifier LIKE '%" + searchTerm +"%'"; searchClause += " OR u.firstname ILIKE '%" + searchTerm +"%'"; searchClause += " OR u.lastname ILIKE '%" + searchTerm +"%'"; searchClause += " OR u.email ILIKE '%" + searchTerm +"%'"; From b58f467c3c39f7ef0536685390effd628a2e311e Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Wed, 7 Jun 2017 15:02:45 -0400 Subject: [PATCH 34/91] #3614, update, thought wasn't working but it was bad data --- .../harvard/iq/dataverse/UserServiceBean.java | 31 +++++++++++++++---- .../iq/dataverse/userdata/UserListMaker.java | 1 - 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 547d7aca511..a8c4f78cbb1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -228,6 +228,13 @@ private List getUserListCore(String searchTerm, String sortKey, Intege //Results of thius query are used to build Authenticated User records + String sharedSearchClause = getSharedSearchClause(searchTerm); + if (sharedSearchClause.isEmpty()){ + sharedSearchClause = ""; + }else{ + sharedSearchClause = " AND " + sharedSearchClause; + } + String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; qstr += " u.affiliation, u.superuser,"; @@ -236,12 +243,17 @@ private List getUserListCore(String searchTerm, String sortKey, Intege qstr += " FROM authenticateduser u,"; qstr += " authenticateduserlookup prov_lookup,"; qstr += " authenticationproviderrow prov"; - qstr += getSharedSearchClause(searchTerm); + qstr += " WHERE"; + qstr += " u.id = prov_lookup.authenticateduser_id"; + qstr += " AND prov_lookup.authenticationproviderid = prov.id"; + qstr += sharedSearchClause; qstr += " ORDER BY u.useridentifier"; qstr += " LIMIT " + resultLimit; qstr += " OFFSET " + offset; qstr += ";"; + System.out.println("getUserCount: " + qstr); + Query nativeQuery = em.createNativeQuery(qstr); return nativeQuery.getResultList(); @@ -260,10 +272,9 @@ private String getSharedSearchClause(String searchTerm){ if (searchTerm.isEmpty()){ return ""; } - - String searchClause = " WHERE"; - searchClause += " u.id = prov_lookup.authenticateduser_id"; - searchClause += " prov_lookup.authenticationproviderid = prov.id"; + + String searchClause = ""; + searchClause += " u.useridentifier LIKE '%" + searchTerm +"%'"; searchClause += " OR u.firstname ILIKE '%" + searchTerm +"%'"; searchClause += " OR u.lastname ILIKE '%" + searchTerm +"%'"; @@ -309,11 +320,19 @@ public Long getUserCount(String searchTerm) { searchTerm = ""; } + String sharedSearchClause = getSharedSearchClause(searchTerm); + if (sharedSearchClause.isEmpty()){ + sharedSearchClause = ""; + }else{ + sharedSearchClause = " WHERE " + sharedSearchClause; + } String qstr = "SELECT count(u.id)"; qstr += " FROM authenticateduser u"; - qstr += getSharedSearchClause(searchTerm); + qstr += sharedSearchClause; qstr += ";"; + System.out.println("getUserCount: " + qstr); + Query nativeQuery = em.createNativeQuery(qstr); return (Long)nativeQuery.getSingleResult(); diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index b3c8885ea05..203f95a3685 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -31,7 +31,6 @@ public class UserListMaker { * Constructor */ public UserListMaker(UserServiceBean userService) { - this.msgt("MyDataFinder, constructor"); this.userService = userService; } From 349d6a24eee6c5cdc586b7dcb269a27dca1e26d5 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Wed, 7 Jun 2017 15:54:14 -0400 Subject: [PATCH 35/91] #3614, add auth provider to column --- src/main/java/Bundle.properties | 2 ++ .../harvard/iq/dataverse/UserServiceBean.java | 5 +++- .../users/AuthenticatedUser.java | 24 +++++++++++++++++++ src/main/resources/META-INF/persistence.xml | 2 +- src/main/webapp/dashboard-users.xhtml | 4 ++++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 094208c8448..ba5e899f6b0 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1646,3 +1646,5 @@ dashboard.list_users.tbl_header.email=Email dashboard.list_users.tbl_header.affiliation=Affiliation dashboard.list_users.tbl_header.roles=Roles dashboard.list_users.tbl_header.isSuperuser=Is Superuser? +dashboard.list_users.tbl_header.authProviderFactoryAlias=Authentication Provider + diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index a8c4f78cbb1..54e3372bc81 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -91,7 +91,7 @@ public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Int .add("position", UserUtil.getStringOrNull(result[7])) .add("modificationTime", UserUtil.getTimestampStringOrNull(result[8])) .add("authProviderId", UserUtil.getStringOrNull(result[9])) - .add("authFactoryAlias", UserUtil.getStringOrNull(result[10])); + .add("authProviderFactoryAlias", UserUtil.getStringOrNull(result[10])); jsonUserListArray.add(singleUserData); } @@ -166,6 +166,9 @@ private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, user.setSuperuser((Boolean)(dbRowValues[6])); user.setPosition(UserUtil.getStringOrNull(dbRowValues[7])); user.setModificationTime(UserUtil.getTimestampOrNull(dbRowValues[8])); + user.setAuthProviderId(UserUtil.getStringOrNull(dbRowValues[9])); + user.setAuthProviderFactoryAlias(UserUtil.getStringOrNull(dbRowValues[10])); + user.setRoles(roles); return user; } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index eed7d7fd005..b49a42918ce 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -158,6 +158,30 @@ public void setRowNum(Integer rowNum) { this.rowNum = rowNum; } + //For User List Admin dashboard - AuthenticatedProviderId + @Transient + private String authProviderId; + + public String getAuthProviderId() { + return authProviderId; + } + + public void setAuthProviderId(String authProviderId) { + this.authProviderId = authProviderId; + } + + + @Transient + private String authProviderFactoryAlias; + + public String getAuthProviderFactoryAlias() { + return authProviderFactoryAlias; + } + + public void setAuthProviderFactoryAlias(String authProviderFactoryAlias) { + this.authProviderFactoryAlias = authProviderFactoryAlias; + } + @Override diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index ecd0c0ba787..9303aa98ea4 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -16,7 +16,7 @@ - + + + + + + + + + - - From 0b81d793ecfc63ef81f284d39b0b776ddf807e60 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 10:42:34 -0400 Subject: [PATCH 39/91] convenience class for returning results #3614 --- .../iq/dataverse/userdata/UserListResult.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java new file mode 100644 index 00000000000..da97be3cbfd --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java @@ -0,0 +1,93 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.userdata; + +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.mydata.Pager; +import java.util.List; +import javax.json.JsonObjectBuilder; + +/** + * + * @author rmp553 + */ +public class UserListResult { + + private String searchTerm; + + private Pager pager; + + private List userList; + + + public UserListResult(String searchTerm, Pager pager, List userList){ + + this.searchTerm = searchTerm; + this.pager = pager; + this.userList = userList; + } + + /** + * Set searchTerm + * @param searchTerm + */ + public void setSearchTerm(String searchTerm){ + this.searchTerm = searchTerm; + } + + /** + * Get for searchTerm + * @return String + */ + public String getSearchTerm(){ + return this.searchTerm; + } + + + /** + * Set pager + * @param pager + */ + public void setPager(Pager pager){ + this.pager = pager; + } + + /** + * Get for pager + * @return Pager + */ + public Pager getPager(){ + return this.pager; + } + + + /** + * Set userList + * @param userList + */ + public void setUserList(List userList){ + this.userList = userList; + } + + /** + * Get for userList + * @return List + */ + public List getUserList(){ + return this.userList; + } + + /** + * TO DO! + * Return this object as a JsonObjectBuilder object + * + * @return + */ + public JsonObjectBuilder asJSON(){ + + return null; + } +} From b05f844937d7130f2d3368ffc1eae8252358701b Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 11:10:44 -0400 Subject: [PATCH 40/91] #3614, work to consolidate biz logic --- .../harvard/iq/dataverse/UserServiceBean.java | 10 ++- .../dashboard/DashboardUsersPage.java | 70 +++++-------------- .../iq/dataverse/userdata/UserListMaker.java | 60 +++++++++++++++- .../iq/dataverse/userdata/UserListResult.java | 57 +++++++++++++++ 4 files changed, 141 insertions(+), 56 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index dad0c88d77b..2d370ed0e24 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -144,17 +144,25 @@ public List getAuthenticatedUserList(String searchTerm, Strin return viewObjects; } + // GATHER GIANT HASHMAP OF ALL USERS + // 1st Loop : + // gather [ @user, .....] + // get the hashmap + + // ------------------------------------------------- // We have results, format them into AuthenticatedUser objects // ------------------------------------------------- int rowNum = offset++; // used for the rowNumber - for (Object[] dbResultRow : userResults) { + for (Object[] dbResultRow : userResults) { + // GET ROLES FOR THIS USER FROM GIANT HASHMAP rowNum++; String roles = getUserRolesAsString((Integer) dbResultRow[0]); AuthenticatedUser singleUser = createAuthenticatedUserForView(dbResultRow, roles, rowNum); viewObjects.add(singleUser); } + return viewObjects; } diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 89486fe6009..7fe23d00357 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -7,11 +7,12 @@ import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.mydata.Pager; -import edu.harvard.iq.dataverse.userdata.OffsetPageValues; import edu.harvard.iq.dataverse.userdata.UserListMaker; +import edu.harvard.iq.dataverse.userdata.UserListResult; import java.text.NumberFormat; import java.util.List; import java.util.Locale; +import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.EJB; import javax.faces.view.ViewScoped; @@ -72,64 +73,25 @@ public boolean runUserSearch(){ /** * (1) Determine the number of users returned by the count */ - Long userCount = userListMaker.getUserCountWithSearch(searchTerm); - - msgt("userCount: " + userCount); - int itemsPerPage = UserListMaker.ITEMS_PER_PAGE; - /** - * (2) Based on the page number and number of users, - * determine the off set to use when querying - */ - OffsetPageValues offsetPageValues = userListMaker.getOffset(userCount, getSelectedPage(), itemsPerPage); - - /** - * Update the pageNumber on the page - */ - setSelectedPage(offsetPageValues.getPageNumber()); - int offset = offsetPageValues.getOffset(); - - msg("offset: " + offset); - - /** - * (3) Run the search and update the user list - */ - String sortKey = null; - this.userList = userService.getAuthenticatedUserList(searchTerm, sortKey, UserListMaker.ITEMS_PER_PAGE, offsetPageValues.getOffset()); - - msg("userList size: " + userList.size()); - - makeNewPager(userCount.intValue(), itemsPerPage, getSelectedPage()); - - msg("pager: " + pager.asJSONString()); - - return true; - } - - /** - * Make sure there is a pager--even if the user count is 0 - * - * @param userCount - * @param displayItemsPerPage - * @param chosenPage - * @return - */ - private boolean makeNewPager(Integer userCount, Integer displayItemsPerPage, Integer chosenPage){ - - if (userCount == null){ - userCount = 0; - } - if (chosenPage == null){ - chosenPage = 1; + UserListResult userListResult = userListMaker.runUserSearch(searchTerm, UserListMaker.ITEMS_PER_PAGE, getSelectedPage(), null); + if (userListResult==null){ + msg("Uh oh!!!!!"); + try { + throw new Exception("userListResult should not be null!"); + } catch (Exception ex) { + Logger.getLogger(DashboardUsersPage.class.getName()).log(Level.SEVERE, null, ex); + } } - if (displayItemsPerPage == null){ - displayItemsPerPage = UserListMaker.ITEMS_PER_PAGE; - } - - pager = new Pager(userCount, displayItemsPerPage, chosenPage); + setSelectedPage(userListResult.getSelectedPageNumber()); + + this.userList = userListResult.getUserList(); + this.pager = userListResult.getPager(); return true; + } + public String getListUsersAPIPath() { //return "ok"; diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index 203f95a3685..421971521e8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -6,8 +6,10 @@ package edu.harvard.iq.dataverse.userdata; import edu.harvard.iq.dataverse.UserServiceBean; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.mydata.Pager; import edu.harvard.iq.dataverse.util.BundleUtil; +import java.util.List; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; @@ -64,8 +66,64 @@ public Long getUserCountWithSearch(String searchTerm){ return userService.getUserCount(searchTerm); } + public UserListResult runUserSearch(String searchTerm, Integer itemsPerPage, Integer selectedPage, String sorKey){ + + // Initialize searchTerm + if ((searchTerm == null) || (searchTerm.trim().isEmpty())){ + searchTerm = null; + } + + // Initialize itemsPerPage + if ((itemsPerPage == null) || (itemsPerPage < 10)){ + itemsPerPage = ITEMS_PER_PAGE; + } + + // Initialize selectedPage + if ((selectedPage == null) || (selectedPage < 1)){ + selectedPage = 1; + } + + // Initialize sortKey + String sortKey = null; + + Pager pager; + + // ------------------------------------------------- + // (1) What is the user count for this search? + // ------------------------------------------------- + Long userCount = userService.getUserCount(searchTerm); + + // Are there any hits? No; return info + if ((userCount == null)||(userCount == 0)){ + pager = new Pager(0, itemsPerPage, selectedPage); + return new UserListResult(searchTerm, pager, null); + } + + // ------------------------------------------------- + // (2) Do some calculations here regarding the selected page, offset, etc. + // ------------------------------------------------- + + OffsetPageValues offsetPageValues = getOffset(userCount, selectedPage, itemsPerPage); + selectedPage = offsetPageValues.getPageNumber(); + int offset = offsetPageValues.getOffset(); + + // ------------------------------------------------- + // (3) Retrieve the users + // ------------------------------------------------- + List userList = userService.getAuthenticatedUserList(searchTerm, sortKey, itemsPerPage, offset); + if (userList ==null){ + pager = new Pager(0, itemsPerPage, selectedPage); + return new UserListResult(searchTerm, pager, null); + } + + pager = new Pager(userCount.intValue(), itemsPerPage, selectedPage); + + return new UserListResult(searchTerm, pager, userList); + + } + /* - * Run the search + * Run the search (API currently) */ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Integer selectedPage, String sorKey){ diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java index da97be3cbfd..16a1cade3ff 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java @@ -7,6 +7,7 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.mydata.Pager; +import java.util.ArrayList; import java.util.List; import javax.json.JsonObjectBuilder; @@ -22,14 +23,33 @@ public class UserListResult { private List userList; + private boolean success; + private String errorMessage; + public UserListResult(String searchTerm, Pager pager, List userList){ + if (searchTerm == null){ + searchTerm = ""; + } this.searchTerm = searchTerm; + this.pager = pager; + this.userList = userList; + if (this.userList == null){ + this.userList = new ArrayList<>(); // new empty list + } } + public Integer getSelectedPageNumber(){ + + if (pager == null){ + return 1; + } + return pager.getSelectedPageNumber(); + } + /** * Set searchTerm * @param searchTerm @@ -90,4 +110,41 @@ public JsonObjectBuilder asJSON(){ return null; } + + + /** + * Set success + * @param success + */ + public void setSuccess(boolean success){ + this.success = success; + } + + /** + * Get for success + * @return boolean + */ + public boolean getSuccess(){ + return this.success; + } + + + + /** + * Set errorMessage + * @param errorMessage + */ + public void setErrorMessage(String errorMessage){ + this.errorMessage = errorMessage; + } + + /** + * Get for errorMessage + * @return String + */ + public String getErrorMessage(){ + return this.errorMessage; + } + + } From b6807a44291e4115fcb83e741e3a2b90f95b7ce6 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 11:35:22 -0400 Subject: [PATCH 41/91] #3614, further consolidation of biz logic. need to finish API part --- .../edu/harvard/iq/dataverse/api/Admin.java | 11 ++- .../dashboard/DashboardUsersPage.java | 1 - .../iq/dataverse/userdata/UserListMaker.java | 32 ++------- .../iq/dataverse/userdata/UserListResult.java | 72 ++++++++++++++++--- 4 files changed, 77 insertions(+), 39 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index f36509f4932..6dd4b0deec7 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -60,6 +60,7 @@ import edu.harvard.iq.dataverse.dataset.DatasetThumbnail; import edu.harvard.iq.dataverse.dataset.DatasetUtil; import edu.harvard.iq.dataverse.userdata.UserListMaker; +import edu.harvard.iq.dataverse.userdata.UserListResult; import edu.harvard.iq.dataverse.util.StringUtil; import javax.inject.Inject; import javax.ws.rs.QueryParam; @@ -337,9 +338,15 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search UserListMaker userListMaker = new UserListMaker(userService); - JsonObjectBuilder userInfo = userListMaker.runSearch(searchTerm, itemsPerPage, selectedPage, null); - return ok(userInfo); + // placeholder + UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, null); + + return ok(userListResult.asJSON()); + + //JsonObjectBuilder userInfo = userListMaker.runSearch(searchTerm, itemsPerPage, selectedPage, null); + + //return ok(userInfo); } diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 7fe23d00357..b576cd1621b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -75,7 +75,6 @@ public boolean runUserSearch(){ */ UserListResult userListResult = userListMaker.runUserSearch(searchTerm, UserListMaker.ITEMS_PER_PAGE, getSelectedPage(), null); if (userListResult==null){ - msg("Uh oh!!!!!"); try { throw new Exception("userListResult should not be null!"); } catch (Exception ex) { diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index 421971521e8..b81e5c2f893 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -7,9 +7,10 @@ import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.datasetutility.OptionalFileParams; import edu.harvard.iq.dataverse.mydata.Pager; -import edu.harvard.iq.dataverse.util.BundleUtil; import java.util.List; +import java.util.logging.Logger; import javax.json.Json; import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; @@ -20,6 +21,8 @@ */ public class UserListMaker { + private static final Logger logger = Logger.getLogger(UserListMaker.class.getName()); + UserServiceBean userService; public boolean errorFound = false; @@ -153,7 +156,7 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte // Are there any hits? No; return info if ((userCount == null)||(userCount == 0)){ - return getNoResultsJSON(); + return null; //getNoResultsJSON(); } // ------------------------------------------------- @@ -176,7 +179,7 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte // ------------------------------------------------- JsonArrayBuilder jsonUserListArray = userService.getUserListAsJSON(searchTerm, sortKey, itemsPerPage, offset); if (jsonUserListArray==null){ - return getNoResultsJSON(); + return null;//getNoResultsJSON(); } Pager pager = new Pager(userCount.intValue(), itemsPerPage, selectedPage); @@ -185,7 +188,7 @@ public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Inte jsonOverallData.add("userCount", userCount) .add("selectedPage", 1) .add("pagination", pager.asJsonObjectBuilder()) - .add("bundleStrings", getBundleStrings()) + //.add("bundleStrings", getBundleStrings()) .add("users", jsonUserListArray) ; return jsonOverallData; @@ -216,27 +219,6 @@ public OffsetPageValues getOffset(Long userCount, Integer selectedPage, Integer } - private JsonObjectBuilder getNoResultsJSON(){ - - return Json.createObjectBuilder() - .add("userCount", 0) - .add("selectedPage", 1) - .add("bundleStrings", getBundleStrings()) - .add("users", Json.createArrayBuilder()); // empty array - } - - public JsonObjectBuilder getBundleStrings(){ - - return Json.createObjectBuilder() - .add("userId", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userId")) - .add("userIdentifier", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userIdentifier")) - .add("lastName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastName")) - .add("firstName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.firstName")) - .add("email", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.email")) - .add("isSuperuser", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.isSuperuser")) - ; - - } public boolean hasError(){ return this.errorFound; diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java index 16a1cade3ff..fa6833b37cc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java @@ -7,8 +7,12 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.mydata.Pager; +import edu.harvard.iq.dataverse.util.BundleUtil; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.json.Json; import javax.json.JsonObjectBuilder; /** @@ -17,6 +21,8 @@ */ public class UserListResult { + private static final Logger logger = Logger.getLogger(UserListResult.class.getName()); + private String searchTerm; private Pager pager; @@ -29,12 +35,16 @@ public class UserListResult { public UserListResult(String searchTerm, Pager pager, List userList){ + if (searchTerm == null){ searchTerm = ""; } this.searchTerm = searchTerm; this.pager = pager; + if (this.pager==null){ + logger.severe("Pager should never be null!"); + } this.userList = userList; if (this.userList == null){ @@ -100,17 +110,6 @@ public List getUserList(){ return this.userList; } - /** - * TO DO! - * Return this object as a JsonObjectBuilder object - * - * @return - */ - public JsonObjectBuilder asJSON(){ - - return null; - } - /** * Set success @@ -146,5 +145,56 @@ public String getErrorMessage(){ return this.errorMessage; } + + /** + * TO DO! + * Return this object as a JsonObjectBuilder object + * + * @return + */ + public JsonObjectBuilder asJSON(){ + + if (userList.isEmpty()){ + return getNoResultsJSON(); + } + if (pager==null){ + logger.severe("Pager should never be null!"); + return getNoResultsJSON(); + + } + + + JsonObjectBuilder jsonOverallData = Json.createObjectBuilder(); + jsonOverallData.add("userCount", pager.getNumResults()) + .add("selectedPage", pager.getSelectedPageNumber()) + .add("pagination", pager.asJsonObjectBuilder()) + .add("bundleStrings", getBundleStrings()) + //.add("users", jsonUserListArray) + ; + return jsonOverallData; + } + + + private JsonObjectBuilder getNoResultsJSON(){ + + return Json.createObjectBuilder() + .add("userCount", 0) + .add("selectedPage", 1) + .add("bundleStrings", getBundleStrings()) + .add("users", Json.createArrayBuilder()); // empty array + } + + public JsonObjectBuilder getBundleStrings(){ + + return Json.createObjectBuilder() + .add("userId", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userId")) + .add("userIdentifier", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userIdentifier")) + .add("lastName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastName")) + .add("firstName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.firstName")) + .add("email", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.email")) + .add("isSuperuser", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.isSuperuser")) + ; + + } } From ef283962c38088d50db11d24e7b3c4110f770cd7 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 11:45:20 -0400 Subject: [PATCH 42/91] placeholder for formatting users as JSON list #3614 --- .../iq/dataverse/userdata/UserListResult.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java index fa6833b37cc..23207b98784 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java @@ -13,6 +13,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.json.Json; +import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; /** @@ -26,13 +27,13 @@ public class UserListResult { private String searchTerm; private Pager pager; - private List userList; private boolean success; private String errorMessage; + public UserListResult(String searchTerm, Pager pager, List userList){ @@ -50,6 +51,7 @@ public UserListResult(String searchTerm, Pager pager, List us if (this.userList == null){ this.userList = new ArrayList<>(); // new empty list } + } public Integer getSelectedPageNumber(){ @@ -162,18 +164,39 @@ public JsonObjectBuilder asJSON(){ return getNoResultsJSON(); } - JsonObjectBuilder jsonOverallData = Json.createObjectBuilder(); jsonOverallData.add("userCount", pager.getNumResults()) .add("selectedPage", pager.getSelectedPageNumber()) .add("pagination", pager.asJsonObjectBuilder()) .add("bundleStrings", getBundleStrings()) - //.add("users", jsonUserListArray) + .add("users", getUsersAsJSONArray()) ; return jsonOverallData; } + + + private JsonArrayBuilder getUsersAsJSONArray(){ + + // ------------------------------------------------- + // No results..... Return count of 0 and empty array + // ------------------------------------------------- + if ((userList==null)||(userList.isEmpty())){ + return Json.createArrayBuilder(); // return an empty array + } + + // ------------------------------------------------- + // We have results, format them into a JSON object + // ------------------------------------------------- + JsonArrayBuilder jsonUserListArray = Json.createArrayBuilder(); + + for (AuthenticatedUser oneUser : userList) { + //jsonUserListArray.add(oneUser.toJSON()); + } + return jsonUserListArray; + } + private JsonObjectBuilder getNoResultsJSON(){ @@ -184,6 +207,11 @@ private JsonObjectBuilder getNoResultsJSON(){ .add("users", Json.createArrayBuilder()); // empty array } + /** + * May be used for table headers or translating field names + * + * @return + */ public JsonObjectBuilder getBundleStrings(){ return Json.createObjectBuilder() From 8806324a7cdd23fb39f90a5a8b6e26894cb71f40 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 12:46:55 -0400 Subject: [PATCH 43/91] updates for role retrieval. appears to work on ui--but paging is off from earlier logic consolidation. #3614 --- .../harvard/iq/dataverse/UserServiceBean.java | 43 ++++++++++-- .../iq/dataverse/userdata/UserListMaker.java | 70 ------------------- 2 files changed, 37 insertions(+), 76 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 2d370ed0e24..81a10639abf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -143,8 +143,23 @@ public List getAuthenticatedUserList(String searchTerm, Strin if (userResults == null){ return viewObjects; } - - // GATHER GIANT HASHMAP OF ALL USERS + + // ------------------------------------------------- + // GATHER GIANT HASHMAP OF ALL { user identifier : [role, role, role] } + // ------------------------------------------------- + + // Iterate through results, retrieving only the assignee identifiers + // Note: userInfo[1], the assigneeIdentifier, cannot be null in the database + // + List identifiers = userResults.stream() + .map(userInfo -> (String)userInfo[1]) + .collect(Collectors.toList()) + ; + + HashMap> roleLookup = retrieveRolesForUsers(identifiers); + if (roleLookup == null){ + roleLookup = new HashMap<>(); + } // 1st Loop : // gather [ @user, .....] // get the hashmap @@ -154,11 +169,18 @@ public List getAuthenticatedUserList(String searchTerm, Strin // We have results, format them into AuthenticatedUser objects // ------------------------------------------------- int rowNum = offset++; // used for the rowNumber - for (Object[] dbResultRow : userResults) { + String roleString; + for (Object[] userInfo : userResults) { // GET ROLES FOR THIS USER FROM GIANT HASHMAP rowNum++; - String roles = getUserRolesAsString((Integer) dbResultRow[0]); - AuthenticatedUser singleUser = createAuthenticatedUserForView(dbResultRow, roles, rowNum); + + //String roles = getUserRolesAsString((Integer) dbResultRow[0]); + roleString = ""; + List roleList = roleLookup.get("@" + (String)userInfo[1]); + if ((roleList != null)&&(!roleList.isEmpty())){ + roleString = roleList.stream().collect(Collectors.joining(", ")); + } + AuthenticatedUser singleUser = createAuthenticatedUserForView(userInfo, roleString, rowNum); viewObjects.add(singleUser); } @@ -197,13 +219,16 @@ private HashMap> retrieveRolesForUsers(List userIde if ((userIdentifierList==null)||(userIdentifierList.isEmpty())){ return null; } - + // Add '@' to each identifier and delimit the list by "," // String identifierList = userIdentifierList.stream() .filter(x -> !Strings.isNullOrEmpty(x)) .map(x -> "'@" + x + "'") .collect(Collectors.joining(", ")); + + System.out.println("identifierList: " + identifierList); + String qstr = "SELECT distinct a.assigneeidentifier,"; qstr += " d.name"; @@ -213,6 +238,8 @@ private HashMap> retrieveRolesForUsers(List userIde qstr += " AND a.assigneeidentifier IN (" + identifierList + ")"; qstr += " ORDER by a.assigneeidentifier, d.name;"; + System.out.println("qstr: " + qstr); + Query nativeQuery = em.createNativeQuery(qstr); List dbRoleResults = nativeQuery.getResultList(); @@ -238,6 +265,10 @@ private HashMap> retrieveRolesForUsers(List userIde } } + System.out.println("userRoleLookup: " + userRoleLookup.size()); + + + return userRoleLookup; } diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index b81e5c2f893..050a06c8ec7 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -7,7 +7,6 @@ import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; -import edu.harvard.iq.dataverse.datasetutility.OptionalFileParams; import edu.harvard.iq.dataverse.mydata.Pager; import java.util.List; import java.util.logging.Logger; @@ -125,75 +124,6 @@ public UserListResult runUserSearch(String searchTerm, Integer itemsPerPage, Int } - /* - * Run the search (API currently) - */ - public JsonObjectBuilder runSearch(String searchTerm, Integer itemsPerPage, Integer selectedPage, String sorKey){ - - // Initialize searchTerm - if ((searchTerm == null) || (searchTerm.trim().isEmpty())){ - searchTerm = null; - } - - // Initialize itemsPerPage - if ((itemsPerPage == null) || (itemsPerPage < 10)){ - itemsPerPage = ITEMS_PER_PAGE; - } - - // Initialize selectedPage - if ((selectedPage == null) || (selectedPage < 1)){ - selectedPage = 1; - } - - // Initialize sortKey - String sortKey = null; - - - // ------------------------------------------------- - // (1) What is the user count for this search? - // ------------------------------------------------- - Long userCount = userService.getUserCount(searchTerm); - - // Are there any hits? No; return info - if ((userCount == null)||(userCount == 0)){ - return null; //getNoResultsJSON(); - } - - // ------------------------------------------------- - // (2) Do some calculations here regarding the selected page, offset, etc. - // ------------------------------------------------- - - OffsetPageValues offsetPageValues = getOffset(userCount, selectedPage, itemsPerPage); - selectedPage = offsetPageValues.getPageNumber(); - int offset = offsetPageValues.getOffset(); - - //int offset = (selectedPage - 1) * itemsPerPage; - //if (offset > userCount){ - // offset = DEFAULT_OFFSET; - // selectedPage = 1; - //} - - - // ------------------------------------------------- - // (3) Retrieve the users - // ------------------------------------------------- - JsonArrayBuilder jsonUserListArray = userService.getUserListAsJSON(searchTerm, sortKey, itemsPerPage, offset); - if (jsonUserListArray==null){ - return null;//getNoResultsJSON(); - } - - Pager pager = new Pager(userCount.intValue(), itemsPerPage, selectedPage); - - JsonObjectBuilder jsonOverallData = Json.createObjectBuilder(); - jsonOverallData.add("userCount", userCount) - .add("selectedPage", 1) - .add("pagination", pager.asJsonObjectBuilder()) - //.add("bundleStrings", getBundleStrings()) - .add("users", jsonUserListArray) - ; - return jsonOverallData; - - } public OffsetPageValues getOffset(Long userCount, Integer selectedPage, Integer itemsPerPage){ From bfd410114edf551ab72c416017df23f934a000cf Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 12:53:16 -0400 Subject: [PATCH 44/91] #3614. user count query now in sync with user retrieval query--fixing pager. BUT indicates a data integrity problem --- .../java/edu/harvard/iq/dataverse/UserServiceBean.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 81a10639abf..ea4d11c7560 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -449,10 +449,15 @@ public Long getUserCount(String searchTerm) { if (sharedSearchClause.isEmpty()){ sharedSearchClause = ""; }else{ - sharedSearchClause = " WHERE " + sharedSearchClause; + sharedSearchClause = " AND " + sharedSearchClause; } String qstr = "SELECT count(u.id)"; - qstr += " FROM authenticateduser u"; + qstr += " FROM authenticateduser u,"; + qstr += " authenticateduserlookup prov_lookup,"; + qstr += " authenticationproviderrow prov"; + qstr += " WHERE"; + qstr += " u.id = prov_lookup.authenticateduser_id"; + qstr += " AND prov_lookup.authenticationproviderid = prov.id"; qstr += sharedSearchClause; qstr += ";"; From 610c48ddc5c53285e4189c993cf318ac4b7df40c Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 12:58:44 -0400 Subject: [PATCH 45/91] remove print stmt #3614 --- .../java/edu/harvard/iq/dataverse/UserServiceBean.java | 6 +++--- src/main/java/edu/harvard/iq/dataverse/api/Admin.java | 9 +-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index ea4d11c7560..d4c22adf72a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -227,7 +227,7 @@ private HashMap> retrieveRolesForUsers(List userIde .map(x -> "'@" + x + "'") .collect(Collectors.joining(", ")); - System.out.println("identifierList: " + identifierList); + //System.out.println("identifierList: " + identifierList); String qstr = "SELECT distinct a.assigneeidentifier,"; @@ -238,7 +238,7 @@ private HashMap> retrieveRolesForUsers(List userIde qstr += " AND a.assigneeidentifier IN (" + identifierList + ")"; qstr += " ORDER by a.assigneeidentifier, d.name;"; - System.out.println("qstr: " + qstr); + //System.out.println("qstr: " + qstr); Query nativeQuery = em.createNativeQuery(qstr); @@ -461,7 +461,7 @@ public Long getUserCount(String searchTerm) { qstr += sharedSearchClause; qstr += ";"; - System.out.println("getUserCount: " + qstr); + //System.out.println("getUserCount: " + qstr); Query nativeQuery = em.createNativeQuery(qstr); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 6dd4b0deec7..00dea77a063 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -334,19 +334,12 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search return error(Response.Status.FORBIDDEN, "forbidden, please leave"); } - //return ok("hey"); - UserListMaker userListMaker = new UserListMaker(userService); + UserListMaker userListMaker = new UserListMaker(userService); - - // placeholder UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, null); return ok(userListResult.asJSON()); - - //JsonObjectBuilder userInfo = userListMaker.runSearch(searchTerm, itemsPerPage, selectedPage, null); - - //return ok(userInfo); } From 27329be8023ea6ff5b879add3f5a9f2ed9a031c0 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Fri, 9 Jun 2017 14:56:16 -0400 Subject: [PATCH 46/91] #3614 Add toJson to Authenticated Users class for api --- .../harvard/iq/dataverse/UserServiceBean.java | 61 +------------------ .../users/AuthenticatedUser.java | 22 +++++++ .../iq/dataverse/userdata/UserListResult.java | 4 +- .../iq/dataverse/userdata/UserUtil.java | 13 ++++ 4 files changed, 38 insertions(+), 62 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index d4c22adf72a..b7192acb545 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -45,66 +45,7 @@ public AuthenticatedUser save( AuthenticatedUser user ) { return user; } - - - - /** - * - * @param searchTerm - * @param sortKey - * @param resultLimit - * @return - */ - public JsonArrayBuilder getUserListAsJSON(String searchTerm, String sortKey, Integer resultLimit, Integer offset) { - - if ((offset == null)||(offset < 0)){ - offset = 0; - } - // ------------------------------------------------- - // Retrieve a list of user attributes from a native query - // ------------------------------------------------- - List userResults = getUserList(searchTerm, sortKey, resultLimit, offset); - - // ------------------------------------------------- - // No results..... Return count of 0 and empty array - // ------------------------------------------------- - if ((userResults==null)||(userResults.isEmpty())){ - return Json.createArrayBuilder(); // return an empty array - } - - // ------------------------------------------------- - // We have results, format them into a JSON object - // ------------------------------------------------- - JsonArrayBuilder jsonUserListArray = Json.createArrayBuilder(); - - offset++; // used for the rowNumber - for (Object[] result : userResults) { - - // not putting explicit nulls for now b/c https://stackoverflow.com/questions/22363925/jsr-353-how-to-add-null-values-using-javax-json-jsonobjectbuilder - // - NullSafeJsonBuilder singleUserData = NullSafeJsonBuilder.jsonObjectBuilder(); - - singleUserData.add("id", (int)result[0]) - .add("rowNum", offset++) - .add("userIdentifier", (String)result[1]) - .add("lastName", UserUtil.getStringOrNull(result[2])) - .add("firstName", UserUtil.getStringOrNull(result[3])) - .add("email", UserUtil.getStringOrNull(result[4])) - .add("affiliation", UserUtil.getStringOrNull(result[5])) - .add("isSuperuser", (boolean)result[6]) - .add("position", UserUtil.getStringOrNull(result[7])) - .add("modificationTime", UserUtil.getTimestampStringOrNull(result[8])) - .add("authProviderId", UserUtil.getStringOrNull(result[9])) - .add("authProviderFactoryAlias", UserUtil.getStringOrNull(result[10])); - - jsonUserListArray.add(singleUserData); - } - - return jsonUserListArray; - - } - - + /** * Return the user information as a List of Arrays--e.g. straight from the db query * diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index b49a42918ce..4745914c0a7 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -5,11 +5,14 @@ import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserLookup; import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider; +import edu.harvard.iq.dataverse.userdata.UserUtil; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import java.io.Serializable; import java.sql.Timestamp; import java.util.List; import java.util.Objects; +import javax.json.Json; +import javax.json.JsonObjectBuilder; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; @@ -304,6 +307,25 @@ public void setShibIdentityProvider(String shibIdentityProvider) { this.shibIdentityProvider = shibIdentityProvider; } + public JsonObjectBuilder toJson() { + JsonObjectBuilder authenicatedUserJson = Json.createObjectBuilder(); + + authenicatedUserJson.add("id", this.id); + authenicatedUserJson.add("rowNum", this.rowNum); + authenicatedUserJson.add("userIdentifier", this.userIdentifier); + authenicatedUserJson.add("lastName", this.lastName); + authenicatedUserJson.add("firstName", this.firstName); + authenicatedUserJson.add("email", this.email); + authenicatedUserJson.add("affiliation", UserUtil.getStringOrBlankForNull(this.affiliation)); + authenicatedUserJson.add("isSuperuser", this.superuser); + authenicatedUserJson.add("position", UserUtil.getStringOrBlankForNull(this.position)); + authenicatedUserJson.add("authenticationProvider", this.authProviderFactoryAlias); + authenicatedUserJson.add("roles", UserUtil.getStringOrBlankForNull(this.roles)); + return authenicatedUserJson; + } + + + @Override public String toString() { return "[AuthenticatedUser identifier:" + getIdentifier() + "]"; diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java index 23207b98784..632234d848a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java @@ -191,8 +191,8 @@ private JsonArrayBuilder getUsersAsJSONArray(){ // ------------------------------------------------- JsonArrayBuilder jsonUserListArray = Json.createArrayBuilder(); - for (AuthenticatedUser oneUser : userList) { - //jsonUserListArray.add(oneUser.toJSON()); + for (AuthenticatedUser oneUser : userList) { + jsonUserListArray.add(oneUser.toJson()); } return jsonUserListArray; } diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java index 7cdc2d098d3..1ec17ac5928 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserUtil.java @@ -27,6 +27,19 @@ public static String getStringOrNull(Object dbResult){ return (String)dbResult; } + /** + * Convenience method to format dbResult + * @param dbResult + * @return + */ + public static String getStringOrBlankForNull(Object dbResult){ + + if (dbResult == null){ + return ""; + } + return (String)dbResult; + } + /** * Convenience method to format dbResult * @param dbResult From c25ce823e5d1b2ff014dde9bd21edbfd46f176f0 Mon Sep 17 00:00:00 2001 From: Leonid Andreev Date: Fri, 9 Jun 2017 15:05:58 -0400 Subject: [PATCH 47/91] Modified the superuser toggling, added a confirmation popup; with the corresponding text in the resource bundle, etc. --- src/main/java/Bundle.properties | 4 ++ .../dashboard/DashboardUsersPage.java | 38 +++++++++++++------ src/main/webapp/dashboard-users.xhtml | 32 +++++++++++----- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index ba5e899f6b0..03687546138 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1647,4 +1647,8 @@ dashboard.list_users.tbl_header.affiliation=Affiliation dashboard.list_users.tbl_header.roles=Roles dashboard.list_users.tbl_header.isSuperuser=Is Superuser? dashboard.list_users.tbl_header.authProviderFactoryAlias=Authentication Provider +dashboard.list_users.toggleSuperuser=Toggle Superuser Status +dashboard.list_users.toggleSuperuser.confirmationText.add=Are you sure you want to give superuser status to user {0}? +dashboard.list_users.toggleSuperuser.confirmationText.remove=Are you sure you want to remove superuser status from user {0}? +dashboard.list_users.toggleSuperuser.confirm=Yes diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index b576cd1621b..8e7dc7b3140 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -152,25 +152,39 @@ public void setSearchTerm(String searchTerm) { this.searchTerm = searchTerm; } - public void toggleSuperUserStatus(AuthenticatedUser user){ - logger.info("Toggling user's "+user.getIdentifier()+" superuser status;"); - user.setSuperuser(!user.isSuperuser()); - logger.info("Attempting to save user "+user.getIdentifier()); - authenticationService.update(user); - - } - - /* Methods for an alternative, two-step implementation: first a confirmation popup, - "are you sure you want to toggle the superuser status of user ...?" - - and if yes, save... + /* + Methods for toggling the supeuser status of a selected user. + Our normal two step approach is used: first showing the "are you sure?" + popup, then finalizing the toggled value. + */ AuthenticatedUser selectedUser = null; + public void setSelectedUser(AuthenticatedUser user) { + this.selectedUser = user; + } + + public AuthenticatedUser getSelectedUser() { + return this.selectedUser; + } + + public void setUserToToggleSuperuserStatus(AuthenticatedUser user) { logger.info("selecting user "+user.getIdentifier()); selectedUser = user; } - */ + public void saveSuperuserStatus(){ + logger.info("Toggling user's "+selectedUser.getIdentifier()+" superuser status; (current status: "+selectedUser.isSuperuser()+")"); + logger.info("Attempting to save user "+selectedUser.getIdentifier()); + authenticationService.update(selectedUser); + + } + + public void cancelSuperuserStatusChange(){ + logger.info("unToggling user's "+selectedUser.getIdentifier()+" superuser status; (current status: "+selectedUser.isSuperuser()+")"); + selectedUser.setSuperuser(!selectedUser.isSuperuser()); + + } private void msg(String s){ System.out.println(s); diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 57a76c90c5e..bae21594a6b 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -22,7 +22,7 @@ - +
@@ -44,7 +44,7 @@ - + @@ -83,16 +83,30 @@ - - - - - - + + + + + + - + + +

+ + + + + + +

+
+ + +
+
From 8f34b0fc988f76027d8972089bf0d0f37fe77a46 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 16:09:58 -0400 Subject: [PATCH 48/91] #3614 nullsafejsonbuilder in AuthenticatedUser.java; add apikey to admin endpoint and turned test mode off for endpoint --- src/main/java/Bundle.properties | 2 ++ .../harvard/iq/dataverse/UserServiceBean.java | 4 --- .../edu/harvard/iq/dataverse/api/Admin.java | 30 +++++++++++++------ .../users/AuthenticatedUser.java | 12 +++++--- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 03687546138..4a23e7f11e0 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1652,3 +1652,5 @@ dashboard.list_users.toggleSuperuser.confirmationText.add=Are you sure you want dashboard.list_users.toggleSuperuser.confirmationText.remove=Are you sure you want to remove superuser status from user {0}? dashboard.list_users.toggleSuperuser.confirm=Yes +dashboard.list_users.api.auth.invalid_apikey=The API key is invalid. +dashboard.list_users.api.auth.not_superuser=Forbidden. You must be a superuser. diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index b7192acb545..e71f0556703 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -3,9 +3,7 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.userdata.UserUtil; -import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.logging.Logger; @@ -13,8 +11,6 @@ import javax.ejb.EJB; import javax.ejb.Stateless; import javax.inject.Named; -import javax.json.Json; -import javax.json.JsonArrayBuilder; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 00dea77a063..f319d56dccf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -9,6 +9,7 @@ import edu.harvard.iq.dataverse.EMailValidator; import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.actionlogging.ActionLogRecord; +import static edu.harvard.iq.dataverse.api.AbstractApiBean.error; import edu.harvard.iq.dataverse.api.dto.RoleDTO; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticationProvider; @@ -52,7 +53,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Response.Status; import java.util.List; -import static edu.harvard.iq.dataverse.api.AbstractApiBean.error; import edu.harvard.iq.dataverse.authorization.AuthTestDataServiceBean; import edu.harvard.iq.dataverse.authorization.RoleAssignee; import edu.harvard.iq.dataverse.authorization.UserRecordIdentifier; @@ -62,6 +62,7 @@ import edu.harvard.iq.dataverse.userdata.UserListMaker; import edu.harvard.iq.dataverse.userdata.UserListResult; import edu.harvard.iq.dataverse.util.StringUtil; +import java.util.ResourceBundle; import javax.inject.Inject; import javax.ws.rs.QueryParam; /** @@ -318,21 +319,32 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search ) { System.out.println("_YE_OLDE_QUERY_COUNTER_"); - boolean DEBUG_MODE = true; - - AuthenticatedUser authUser = null; - + boolean DEBUG_MODE = false; // DANGER HERE! Make sure it's false! + if (DEBUG_MODE==true){ // DEBUG: use userIdentifier - //return ok("hello! (debug)"); + // DEBUG MODE, pass on by to the actual logic } else if ((session.getUser() != null)&&(session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())){ - authUser = (AuthenticatedUser)session.getUser(); + // Looks good, we have an authenticated superuser }else{ - return error(Response.Status.FORBIDDEN, "forbidden, please leave"); - + + User authUser; + try { + authUser = this.findUserOrDie(); + } catch (AbstractApiBean.WrappedResponse ex) { + return error(Response.Status.FORBIDDEN, + ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.invalid_apikey") + ); + } + + if (!authUser.isSuperuser()){ + return error(Response.Status.FORBIDDEN, + ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.not_superuser")); + } + // } UserListMaker userListMaker = new UserListMaker(userService); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 4745914c0a7..1362a462267 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -7,6 +7,7 @@ import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider; import edu.harvard.iq.dataverse.userdata.UserUtil; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; +import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.io.Serializable; import java.sql.Timestamp; import java.util.List; @@ -308,19 +309,22 @@ public void setShibIdentityProvider(String shibIdentityProvider) { } public JsonObjectBuilder toJson() { - JsonObjectBuilder authenicatedUserJson = Json.createObjectBuilder(); + //JsonObjectBuilder authenicatedUserJson = Json.createObjectBuilder(); + NullSafeJsonBuilder authenicatedUserJson = NullSafeJsonBuilder.jsonObjectBuilder(); + authenicatedUserJson.add("id", this.id); authenicatedUserJson.add("rowNum", this.rowNum); authenicatedUserJson.add("userIdentifier", this.userIdentifier); authenicatedUserJson.add("lastName", this.lastName); authenicatedUserJson.add("firstName", this.firstName); authenicatedUserJson.add("email", this.email); - authenicatedUserJson.add("affiliation", UserUtil.getStringOrBlankForNull(this.affiliation)); + authenicatedUserJson.add("affiliation", UserUtil.getStringOrNull(this.affiliation)); authenicatedUserJson.add("isSuperuser", this.superuser); - authenicatedUserJson.add("position", UserUtil.getStringOrBlankForNull(this.position)); + authenicatedUserJson.add("position", UserUtil.getStringOrNull(this.position)); authenicatedUserJson.add("authenticationProvider", this.authProviderFactoryAlias); - authenicatedUserJson.add("roles", UserUtil.getStringOrBlankForNull(this.roles)); + authenicatedUserJson.add("roles", UserUtil.getStringOrNull(this.roles)); + return authenicatedUserJson; } From 8dc5dbe3647be3c9784665e1f7d940eb973d1c65 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 16:14:10 -0400 Subject: [PATCH 49/91] add deprecated take to previous endpoint for listing users--e.g. that always listed ALL users --- src/main/java/edu/harvard/iq/dataverse/api/Admin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index f319d56dccf..6a7620e60bc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -290,6 +290,7 @@ public Response publishDataverseAsCreator(@PathParam("id") long id) { } } + @Deprecated @GET @Path("authenticatedUsers") public Response listAuthenticatedUsers() { From 4854b5c9f96c7e1005f52631308c4e624c2e9acd Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 9 Jun 2017 16:26:20 -0400 Subject: [PATCH 50/91] #3614 convenience method for adding commans to startCardNumber and endCardNumber in the pager' --- .../java/edu/harvard/iq/dataverse/mydata/Pager.java | 11 +++++++++++ src/main/webapp/dashboard-users-pager.xhtml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java index 5e7c1d16e6d..c2fc87c667d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java @@ -49,6 +49,9 @@ public class Pager { public int startCardNumber = 0; public int endCardNumber = 0; + public String startCardNumberString; + public String endCardNumberString; + public int remainingCards = 0; public int numberNextResults =0; @@ -292,7 +295,11 @@ public int getStartCardNumber(){ return this.startCardNumber; } + public String getStartCardNumberString(){ + + return this.addCommasToNumber(startCardNumber); + } /** * @param startCardNumber */ @@ -309,7 +316,11 @@ public int getEndCardNumber(){ return this.endCardNumber; } + public String getEndCardNumberString(){ + + return this.addCommasToNumber(endCardNumber); + } /** * @param endCardNumber */ diff --git a/src/main/webapp/dashboard-users-pager.xhtml b/src/main/webapp/dashboard-users-pager.xhtml index 05e32b3faff..13449107cc7 100644 --- a/src/main/webapp/dashboard-users-pager.xhtml +++ b/src/main/webapp/dashboard-users-pager.xhtml @@ -21,7 +21,7 @@ -
Displaying: #{listPager.startCardNumber} to #{listPager.endCardNumber} +
Displaying: #{listPager.startCardNumberString} to #{listPager.endCardNumberString}

From c8813b55ed6e549e4975864dc0a531bc84eba534 Mon Sep 17 00:00:00 2001 From: Michael Heppler Date: Fri, 9 Jun 2017 16:36:52 -0400 Subject: [PATCH 51/91] Cleaned up UI of Manage Users pg. [ref #3614] --- src/main/java/Bundle.properties | 52 +++++++------ src/main/webapp/dashboard-users-pager.xhtml | 84 ++++++++------------- src/main/webapp/dashboard-users.xhtml | 27 +++---- src/main/webapp/dashboard.xhtml | 8 +- 4 files changed, 75 insertions(+), 96 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 4a23e7f11e0..45f46edf15c 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -53,6 +53,8 @@ yes=Yes no=No previous=Previous next=Next +first=First +last=Last more=More... less=Less... select=Select... @@ -496,6 +498,31 @@ harvestserver.newSetDialog.success=Successfully created harvesting set "{0}". harvestserver.viewEditDialog.title=Edit Harvesting Set harvestserver.viewEditDialog.btn.save=Save Changes +#dashboard-users.xhtml +dashboard.card.users=Users +dashboard.card.users.super=Superusers +dashboard.card.users.manage=Manage Users +dashboard.card.users.message=List and manage users. +dashboard.list_users.searchTerm.watermark=Search these users... + +dashboard.list_users.tbl_header.rowNumber=# +dashboard.list_users.tbl_header.userId=User ID +dashboard.list_users.tbl_header.userIdentifier=Username +dashboard.list_users.tbl_header.lastName=Last Name +dashboard.list_users.tbl_header.firstName=First Name +dashboard.list_users.tbl_header.email=Email +dashboard.list_users.tbl_header.affiliation=Affiliation +dashboard.list_users.tbl_header.roles=Roles +dashboard.list_users.tbl_header.isSuperuser=Superuser +dashboard.list_users.tbl_header.authProviderFactoryAlias=Authentication +dashboard.list_users.toggleSuperuser=Enable Superuser +dashboard.list_users.toggleSuperuser.confirmationText.add=Are you sure you want to enable superuser status for user {0}? +dashboard.list_users.toggleSuperuser.confirmationText.remove=Are you sure you want to disable superuser status for user {0}? +dashboard.list_users.toggleSuperuser.confirm=Continue + +dashboard.list_users.api.auth.invalid_apikey=The API key is invalid. +dashboard.list_users.api.auth.not_superuser=Forbidden. You must be a superuser. + #MailServiceBean.java notification.email.create.dataverse.subject=Dataverse: Your dataverse has been created @@ -1630,27 +1657,4 @@ citationFrame.banner.message=If the site below does not load, the archived data citationFrame.banner.message.here=here citationFrame.banner.closeIcon=Close this message, go to dataset citationFrame.banner.countdownMessage= This message will close in -citationFrame.banner.countdownMessage.seconds=seconds - -dashboard.card.users.header=Users -dashboard.card.users.message=List and manage users. -dashboard.card.users.btn.manage=Manage Users -dashboard.list_users.searchTerm.watermark=Search these users... - -dashboard.list_users.tbl_header.rowNumber=# -dashboard.list_users.tbl_header.userId=User ID -dashboard.list_users.tbl_header.userIdentifier=User name -dashboard.list_users.tbl_header.lastName=Last Name -dashboard.list_users.tbl_header.firstName=First Name -dashboard.list_users.tbl_header.email=Email -dashboard.list_users.tbl_header.affiliation=Affiliation -dashboard.list_users.tbl_header.roles=Roles -dashboard.list_users.tbl_header.isSuperuser=Is Superuser? -dashboard.list_users.tbl_header.authProviderFactoryAlias=Authentication Provider -dashboard.list_users.toggleSuperuser=Toggle Superuser Status -dashboard.list_users.toggleSuperuser.confirmationText.add=Are you sure you want to give superuser status to user {0}? -dashboard.list_users.toggleSuperuser.confirmationText.remove=Are you sure you want to remove superuser status from user {0}? -dashboard.list_users.toggleSuperuser.confirm=Yes - -dashboard.list_users.api.auth.invalid_apikey=The API key is invalid. -dashboard.list_users.api.auth.not_superuser=Forbidden. You must be a superuser. +citationFrame.banner.countdownMessage.seconds=seconds \ No newline at end of file diff --git a/src/main/webapp/dashboard-users-pager.xhtml b/src/main/webapp/dashboard-users-pager.xhtml index 13449107cc7..af27fc2f82b 100644 --- a/src/main/webapp/dashboard-users-pager.xhtml +++ b/src/main/webapp/dashboard-users-pager.xhtml @@ -2,54 +2,39 @@ xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:jsf="http://xmlns.jcp.org/jsf" xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"> - - - -
- -
-
- - Found: #{listPager.numResultsString} results - - - Found: #{listPager.numResultsString} result - - - -
Displaying: #{listPager.startCardNumberString} to #{listPager.endCardNumberString} -
-
-
- -
- -   - - - - -
- +
\ No newline at end of file diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index bae21594a6b..da8334dba39 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -13,9 +13,10 @@ - - + + + @@ -45,29 +46,25 @@ - + + + + + - - - - - - + + - - - - @@ -104,7 +101,7 @@

- +
diff --git a/src/main/webapp/dashboard.xhtml b/src/main/webapp/dashboard.xhtml index 764978cf1b1..53e6e8ca312 100644 --- a/src/main/webapp/dashboard.xhtml +++ b/src/main/webapp/dashboard.xhtml @@ -104,21 +104,21 @@
-

#{bundle['dashboard.card.users.header']}

+

#{bundle['dashboard.card.users']}

-

Users

+

#{bundle['dashboard.card.users']}

-

Super-Users

+

#{bundle['dashboard.card.users.super']}

From a9b513e6f2b99ef637b4732583a25eaf510b4659 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 12 Jun 2017 09:43:57 -0400 Subject: [PATCH 52/91] cleaning up cruft #3614 --- .../harvard/iq/dataverse/MailServiceBean.java | 3 +- .../harvard/iq/dataverse/UserServiceBean.java | 3 - .../edu/harvard/iq/dataverse/api/Admin.java | 1 - .../dashboard/DashboardUsersPage.java | 3 +- .../webapp/mydata_templates/user_list.html | 63 ----------- .../webapp/resources/js/dashboard_users.js | 102 ------------------ 6 files changed, 2 insertions(+), 173 deletions(-) delete mode 100644 src/main/webapp/mydata_templates/user_list.html delete mode 100644 src/main/webapp/resources/js/dashboard_users.js diff --git a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java index f1ec1795519..aea07f8f3bf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java @@ -101,7 +101,6 @@ public void sendMail(String host, String from, String to, String subject, String private Session session; public boolean sendSystemEmail(String to, String subject, String messageText) { - if (true) return true; boolean sent = false; String body = messageText + ResourceBundle.getBundle("Bundle").getString("notification.email.closing"); @@ -181,7 +180,7 @@ public void sendMail(String from, String to, String subject, String messageText, } public Boolean sendNotificationEmail(UserNotification notification){ - if (true) return true; + boolean retval = false; String emailAddress = getUserEmailAddress(notification); if (emailAddress != null){ diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index e71f0556703..76e91f36876 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -202,9 +202,6 @@ private HashMap> retrieveRolesForUsers(List userIde } } - System.out.println("userRoleLookup: " + userRoleLookup.size()); - - return userRoleLookup; } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 6a7620e60bc..18c0b0e9094 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -318,7 +318,6 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search @QueryParam("numDisplay") Integer itemsPerPage, @QueryParam("sortKey") String sortKey ) { - System.out.println("_YE_OLDE_QUERY_COUNTER_"); boolean DEBUG_MODE = false; // DANGER HERE! Make sure it's false! diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 8e7dc7b3140..2b76abf8802 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -44,7 +44,6 @@ public class DashboardUsersPage implements java.io.Serializable { private String searchTerm; public String init() { - System.out.println("_YE_OLDE_QUERY_COUNTER_"); // for debug purposes if ((session.getUser() != null) && (session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())) { authUser = (AuthenticatedUser) session.getUser(); @@ -187,7 +186,7 @@ public void cancelSuperuserStatusChange(){ } private void msg(String s){ - System.out.println(s); + //System.out.println(s); } private void msgt(String s){ diff --git a/src/main/webapp/mydata_templates/user_list.html b/src/main/webapp/mydata_templates/user_list.html deleted file mode 100644 index 6bb25e3147a..00000000000 --- a/src/main/webapp/mydata_templates/user_list.html +++ /dev/null @@ -1,63 +0,0 @@ -String getCitation(){ - > Backing bean - > get Dataset - to JSON -> Lots of RestAssuredTEsts - to DatasetJSONMap - - JSON Excel Metadata - { - numRows: - } - - - Utility: - > getDatasetCard(DatasetJSONMap){ - return DatasetJSONMap + template = HTML String - } - - - > getCitation(DatasetJSONMap){ - return DatasetJSONMap + template = HTML String - } - getJSONSchema(DatasetJSONMap){ - return DatasetJSONMap + template = HTML String - } - getDublinCoreMetaHTML(DatasetJSONMap){ - return DatasetJSONMap + template = HTML String - } - datasetJSONMap -} - -
- - - - - - - - - - - - - {% for name_info in data.users -%} - - - - - - - - - - {% else %} - - - - {% endfor %} - -
#{{ data.bundleStrings.userIdentifier }}{{ data.bundleStrings.lastName }}{{ data.bundleStrings.firstName }}{{ data.bundleStrings.email }}{{ data.bundleStrings.userId }}{{ data.bundleStrings.isSuperuser }}
{{ name_info.rowNum }}{{ name_info.userIdentifier }}{{ name_info.lastName }}{{ name_info.firstName }}{{ name_info.email }}{{ name_info.id }}{{ name_info.isSuperuser }}
Sorry. No users found.
- - - diff --git a/src/main/webapp/resources/js/dashboard_users.js b/src/main/webapp/resources/js/dashboard_users.js deleted file mode 100644 index f0a8be4f16d..00000000000 --- a/src/main/webapp/resources/js/dashboard_users.js +++ /dev/null @@ -1,102 +0,0 @@ - -var USER_LIST_DEBUG_ON = false; - -function initPage(){ - nunjucks.configure({ autoescape: true }); - bindReturnKeyOnSearch(); - runRegularSearch(); -} - -function clearUserList(){ - $('#div-user-list').html(''); -} - -function clearWarningMessage(){ - $('#div-result-message').html(''); -} - -function setWarningAlert(alert_msg){ - var alert_html = ''; - $('#div-result-message').html(alert_html); -} - -function runRegularSearch(){ - - clearWarningMessage(); - clearUserList(); - - //var selectedPage = $("#selectedPage").val(); - //var searchTerm = $("#searchTerm").val(); - var formData = $("#selectedPage").serialize() + '&' + $("#searchTerm").serialize(); - - // Call the API endpoint - $.getJSON( RETRIEVE_USER_DATA_API_PATH + '?' + formData, function(data) { - - // For debugging, show the returned JSON - if (USER_LIST_DEBUG_ON){ - $("#div-json-results").html(JSON.stringify(data)); - } - - // Didn't work, show error - if ((!data.status)||(!data.status == 'OK')){ - setWarningAlert(data.errorMessage); - return; - } - - // Looks good, let's make a page - - // -------------------------------- - // (3) If JSON has pagination info, make a pager - // -------------------------------- - updatePagination(data); - - // -------------------------------- - // (4) Let's list the users - // -------------------------------- - // pass the list of names to the template - var user_list_html = nunjucks.render('mydata_templates/user_list.html', data); - $("#div-user-list").html(user_list_html); - - - }); -} - - -function updatePagination(json_data){ - // console.log(json_data); - $("#div-pagination").html(''); - if (json_data.data.hasOwnProperty('pagination')){ - var pagination_json = json_data.data.pagination; - // Use nunjucks to create the pagination HTML - var pagination_html = nunjucks.render('mydata_templates/pagination.html', pagination_json); - // Put the pagination HTML into the div - $("#div-pagination").html(pagination_html); - - bindPages(); - } -} - -//----------------------------------------- -// Bind pager buttons -//----------------------------------------- -function bindPages(){ - // bind pager buttons - $("a.page_link").click(function(evt) { - evt.preventDefault(); // stop link from using href - var page_num = $(this).attr('rel'); - $("#selectedPage").val(page_num); // update the selected page in the form - runRegularSearch(); // run search - }); -} - -function bindReturnKeyOnSearch(){ - - // Capture pressing return in search box - $('#searchTerm').keypress(function(e) { - if (e.which == '13') { - e.preventDefault(); - $("#selectedPage").val('1'); - runRegularSearch(); - } - }); -} From 23a2910ee48bcd42124cfe097a08418ffeeec126 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 12 Jun 2017 09:53:12 -0400 Subject: [PATCH 53/91] #3614 - removing more cruft. add bundle for user list page header --- src/main/java/Bundle.properties | 1 + .../iq/dataverse/dashboard/DashboardUsersPage.java | 11 +---------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 45f46edf15c..cb5773477df 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -500,6 +500,7 @@ harvestserver.viewEditDialog.btn.save=Save Changes #dashboard-users.xhtml dashboard.card.users=Users +dashboard.card.users.header=Dashboard - User List dashboard.card.users.super=Superusers dashboard.card.users.manage=Manage Users dashboard.card.users.message=List and manage users. diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 2b76abf8802..f13aab7804e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -66,7 +66,7 @@ public boolean runUserSearchWithPage(Integer pageNumber){ public boolean runUserSearch(){ - msgt("Run the search!"); + logger.fine("Run the search!"); /** @@ -185,14 +185,5 @@ public void cancelSuperuserStatusChange(){ } - private void msg(String s){ - //System.out.println(s); - } - - private void msgt(String s){ - msg("-------------------------------"); - msg(s); - msg("-------------------------------"); - } } From eae1818f788b1a051adca403f93cb5d7b5963890 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 13 Jun 2017 12:39:51 -0400 Subject: [PATCH 54/91] #3614, updates from code review --- .../harvard/iq/dataverse/UserServiceBean.java | 12 +++++++++--- .../dataverse/userdata/OffsetPageValues.java | 18 +++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 76e91f36876..7a5443aea50 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; import javax.ejb.EJB; @@ -128,7 +129,8 @@ public List getAuthenticatedUserList(String searchTerm, Strin private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, String roles, int rowNum){ AuthenticatedUser user = new AuthenticatedUser(); user.setRowNum(rowNum); - user.setId(new Long((Integer)dbRowValues[0])); + + user.setId(new Long((int)dbRowValues[0])); user.setUserIdentifier((String)dbRowValues[1]); user.setLastName(UserUtil.getStringOrNull(dbRowValues[2])); user.setFirstName(UserUtil.getStringOrNull(dbRowValues[3])); @@ -241,6 +243,10 @@ private String getUserRolesAsString(Integer userId) { } /** + * + * Run a native query, returning a List containing + * AuthenticatedUser information as well as information about the + * Authenticated Provider (e.g. builtin user, etc) * * @param searchTerm * @param sortKey @@ -293,7 +299,7 @@ private List getUserListCore(String searchTerm, String sortKey, Intege qstr += " OFFSET " + offset; qstr += ";"; - System.out.println("getUserCount: " + qstr); + logger.log(Level.FINE, "getUserCount: {0}", qstr); Query nativeQuery = em.createNativeQuery(qstr); @@ -365,7 +371,7 @@ public Long getSuperUserCount() { */ public Long getTotalUserCount(){ - return getUserCount(null); + return getUserCount(""); } /** diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java b/src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java index 719546a346c..c46e8816907 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/OffsetPageValues.java @@ -11,14 +11,14 @@ */ public class OffsetPageValues { - private Integer offset; - private Integer pageNumber; + private int offset; + private int pageNumber; /* * Constructor */ - public OffsetPageValues(Integer offset, Integer pageNumber) { + public OffsetPageValues(int offset, int pageNumber) { this.pageNumber = pageNumber; this.offset = offset; } @@ -29,15 +29,15 @@ public OffsetPageValues(Integer offset, Integer pageNumber) { * Set offset * @param offset */ - public void setOffset(Integer offset){ + public void setOffset(int offset){ this.offset = offset; } /** * Get for offset - * @return Integer + * @return int */ - public Integer getOffset(){ + public int getOffset(){ return this.offset; } @@ -46,15 +46,15 @@ public Integer getOffset(){ * Set pageNumber * @param pageNumber */ - public void setPageNumber(Integer pageNumber){ + public void setPageNumber(int pageNumber){ this.pageNumber = pageNumber; } /** * Get for pageNumber - * @return Integer + * @return int */ - public Integer getPageNumber(){ + public int getPageNumber(){ return this.pageNumber; } From f1d0f7f553f1e2e4f6dcff6ca1cd825e5f3241f0 Mon Sep 17 00:00:00 2001 From: Leonid Andreev Date: Tue, 13 Jun 2017 15:00:06 -0400 Subject: [PATCH 55/91] Added a query.setParameter() to pass the search term to the native query, per code review request. --- .../harvard/iq/dataverse/UserServiceBean.java | 74 ++++++++----------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 7a5443aea50..92fc446fe20 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -273,15 +273,18 @@ private List getUserListCore(String searchTerm, String sortKey, Intege offset = 0; } - //Results of thius query are used to build Authenticated User records + //Results of this query are used to build Authenticated User records: - String sharedSearchClause = getSharedSearchClause(searchTerm); - if (sharedSearchClause.isEmpty()){ - sharedSearchClause = ""; - }else{ - sharedSearchClause = " AND " + sharedSearchClause; + searchTerm = searchTerm.trim(); + + + String sharedSearchClause = ""; + + if (!searchTerm.isEmpty()) { + sharedSearchClause = " AND " + getSharedSearchClause(); } + String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; qstr += " u.affiliation, u.superuser,"; @@ -301,7 +304,8 @@ private List getUserListCore(String searchTerm, String sortKey, Intege logger.log(Level.FINE, "getUserCount: {0}", qstr); - Query nativeQuery = em.createNativeQuery(qstr); + Query nativeQuery = em.createNativeQuery(qstr); + nativeQuery.setParameter("searchTerm", searchTerm + "%"); return nativeQuery.getResultList(); @@ -312,38 +316,15 @@ private List getUserListCore(String searchTerm, String sortKey, Intege * (1) get a user count * (2) get a list of users * - * @param searchTerm * @return */ - private String getSharedSearchClause(String searchTerm){ - if (searchTerm == null){ - return ""; - } - - String searchClause = ""; - - searchTerm = searchTerm.trim(); - if (searchTerm.isEmpty()){ - return ""; - } - - //-------------------------------------------------------- - // Search for term anywhere at beginning of string - //-------------------------------------------------------- - searchClause += " (u.useridentifier LIKE '" + searchTerm +"%'"; - searchClause += " OR u.firstname ILIKE '" + searchTerm +"%'"; - searchClause += " OR u.lastname ILIKE '" + searchTerm +"%'"; - searchClause += " OR u.email ILIKE '" + searchTerm +"%')"; - - /* - //-------------------------------------------------------- - // Search for term anywhere in string - //-------------------------------------------------------- - searchClause += " u.useridentifier LIKE '%" + searchTerm +"%'"; - searchClause += " OR u.firstname ILIKE '%" + searchTerm +"%'"; - searchClause += " OR u.lastname ILIKE '%" + searchTerm +"%'"; - searchClause += " OR u.email ILIKE '%" + searchTerm +"%'"; - */ + private String getSharedSearchClause(){ + + String searchClause = " (u.useridentifier ILIKE #searchTerm"; + searchClause += " OR u.firstname ILIKE #searchTerm"; + searchClause += " OR u.lastname ILIKE #searchTerm"; + searchClause += " OR u.email ILIKE #searchTerm)"; + return searchClause; } @@ -383,16 +364,18 @@ public Long getUserCount(String searchTerm) { if ((searchTerm==null)||(searchTerm.isEmpty())){ searchTerm = ""; - } + } + searchTerm = searchTerm.trim(); - String sharedSearchClause = getSharedSearchClause(searchTerm); - if (sharedSearchClause.isEmpty()){ - sharedSearchClause = ""; - }else{ - sharedSearchClause = " AND " + sharedSearchClause; + + String sharedSearchClause = ""; + + if (!searchTerm.isEmpty()) { + sharedSearchClause = " AND " + getSharedSearchClause(); } + String qstr = "SELECT count(u.id)"; - qstr += " FROM authenticateduser u,"; + qstr += " FROM authenticateduser u,"; qstr += " authenticateduserlookup prov_lookup,"; qstr += " authenticationproviderrow prov"; qstr += " WHERE"; @@ -403,7 +386,8 @@ public Long getUserCount(String searchTerm) { //System.out.println("getUserCount: " + qstr); - Query nativeQuery = em.createNativeQuery(qstr); + Query nativeQuery = em.createNativeQuery(qstr); + nativeQuery.setParameter("searchTerm", searchTerm + "%"); return (Long)nativeQuery.getSingleResult(); From 8c85514f675fdfde0a3c9ccda50f63d4eebe21b5 Mon Sep 17 00:00:00 2001 From: Leonid Andreev Date: Tue, 20 Jun 2017 23:14:36 -0400 Subject: [PATCH 56/91] Added native queries (two, per page load) to look up user roles assigned through group membership. --- .../harvard/iq/dataverse/UserServiceBean.java | 133 ++++++++++++++++-- 1 file changed, 120 insertions(+), 13 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 92fc446fe20..b45d0e7d4c5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -15,6 +15,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; +import org.apache.commons.lang.StringUtils; import org.ocpsoft.common.util.Strings; @Stateless @@ -86,15 +87,8 @@ public List getAuthenticatedUserList(String searchTerm, Strin // GATHER GIANT HASHMAP OF ALL { user identifier : [role, role, role] } // ------------------------------------------------- - // Iterate through results, retrieving only the assignee identifiers - // Note: userInfo[1], the assigneeIdentifier, cannot be null in the database - // - List identifiers = userResults.stream() - .map(userInfo -> (String)userInfo[1]) - .collect(Collectors.toList()) - ; - - HashMap> roleLookup = retrieveRolesForUsers(identifiers); + + HashMap> roleLookup = retrieveRolesForUsers(userResults); if (roleLookup == null){ roleLookup = new HashMap<>(); } @@ -153,7 +147,19 @@ private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, * @param userIdentifierList * @return */ - private HashMap> retrieveRolesForUsers(List userIdentifierList){ + private HashMap> retrieveRolesForUsers(List userObjectList){ + // Iterate through results, retrieving only the assignee identifiers + // Note: userInfo[1], the assigneeIdentifier, cannot be null in the database + // + List userIdentifierList = userObjectList.stream() + .map(userInfo -> (String)userInfo[1]) + .collect(Collectors.toList()) + ; + + List databaseIds = userObjectList.stream() + .map(userInfo -> (Integer)userInfo[0]) + .collect(Collectors.toList()); + if ((userIdentifierList==null)||(userIdentifierList.isEmpty())){ return null; @@ -161,12 +167,12 @@ private HashMap> retrieveRolesForUsers(List userIde // Add '@' to each identifier and delimit the list by "," // - String identifierList = userIdentifierList.stream() + String identifierListString = userIdentifierList.stream() .filter(x -> !Strings.isNullOrEmpty(x)) .map(x -> "'@" + x + "'") .collect(Collectors.joining(", ")); - //System.out.println("identifierList: " + identifierList); + //System.out.println("identifierListString: " + identifierListString); String qstr = "SELECT distinct a.assigneeidentifier,"; @@ -174,7 +180,7 @@ private HashMap> retrieveRolesForUsers(List userIde qstr += " FROM roleassignment a,"; qstr += " dataverserole d"; qstr += " WHERE d.id = a.role_id"; - qstr += " AND a.assigneeidentifier IN (" + identifierList + ")"; + qstr += " AND a.assigneeidentifier IN (" + identifierListString + ")"; qstr += " ORDER by a.assigneeidentifier, d.name;"; //System.out.println("qstr: " + qstr); @@ -204,6 +210,107 @@ private HashMap> retrieveRolesForUsers(List userIde } } + // And now the roles assigned via groups: + + + // 1. One query for selecting all the groups to which these users may belong: + + HashMap> groupsLookup = new HashMap<>(); + + String idListString = StringUtils.join(databaseIds, ","); + + qstr = "SELECT distinct g.groupalias, "; + qstr += " u.useridentifier"; + qstr += " FROM explicitgroup g,"; + qstr += " explicitgroup_authenticateduser e, "; + qstr += " authenticateduser u"; + qstr += " WHERE e.explicitgroup_id = g.id"; + qstr += " AND e.containedauthenticatedusers_id IN (" + idListString + ")"; + qstr += " AND u.id = e.containedauthenticatedusers_id"; + qstr += " ORDER by g.groupalias"; + + + //System.out.println("qstr: " + qstr); + + nativeQuery = em.createNativeQuery(qstr); + List groupResults = nativeQuery.getResultList(); + if (groupResults == null){ + return userRoleLookup; + } + + String groupIdentifiers = null; + + for (Object group[] : groupResults) { + String alias = UserUtil.getStringOrNull(group[0]); + String user = UserUtil.getStringOrNull(group[1]); + if (alias != null ) { + + alias = "&explicit/"+alias; + + if (groupIdentifiers == null) { + groupIdentifiers = "'"+alias+"'"; + } else { + groupIdentifiers += ", '"+alias+"'"; + } + + List groupUserList = groupsLookup.getOrDefault(alias, new ArrayList()); + if (!groupUserList.contains(user)){ + groupUserList.add(user); + groupsLookup.put(alias, groupUserList); + } + } + } + + // 2. And now we can make another lookup on the roleassignment table, using the list + // of the explicit group aliases we have just generated: + + if (groupIdentifiers == null) { + return userRoleLookup; + } + + qstr = "SELECT distinct a.assigneeidentifier,"; + qstr += " d.name"; + qstr += " FROM roleassignment a,"; + qstr += " dataverserole d"; + qstr += " WHERE d.id = a.role_id"; + qstr += " AND a.assigneeidentifier IN ("; + qstr += groupIdentifiers; + qstr += ") ORDER by a.assigneeidentifier, d.name;"; + + //System.out.println("qstr: " + qstr); + + nativeQuery = em.createNativeQuery(qstr); + + dbRoleResults = nativeQuery.getResultList(); + if (dbRoleResults == null){ + return userRoleLookup; + } + + + for (Object[] dbResultRow : dbRoleResults) { + + String groupIdentifier = UserUtil.getStringOrNull(dbResultRow[0]); + String groupRole = UserUtil.getStringOrNull(dbResultRow[1]); + if ((groupIdentifier != null)&&(groupRole != null)){ // should never be null + + List groupUserList = groupsLookup.get(groupIdentifier); + + if (groupUserList != null) { + + for (String groupUserIdentifier : groupUserList) { + groupUserIdentifier = "@" + groupUserIdentifier; + //System.out.println("Group user: "+groupUserIdentifier); + List userRoleList = userRoleLookup.getOrDefault(groupUserIdentifier, new ArrayList()); + if (!userRoleList.contains(groupRole)){ + //System.out.println("User Role: "+groupRole); + userRoleList.add(groupRole); + userRoleLookup.put(groupUserIdentifier, userRoleList); + } + } + } + } + } + return userRoleLookup; } From 4feb4a693a5cf00ae27ebc05c80844df64bbd6bf Mon Sep 17 00:00:00 2001 From: Leonid Andreev Date: Wed, 21 Jun 2017 12:14:32 -0400 Subject: [PATCH 57/91] Added recursion to the native query that looks up role assignments inhereted via group membership; so that it finds all the groups to which the specified users may belong, both by direct inclusion, and via parent groups. --- .../harvard/iq/dataverse/UserServiceBean.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index b45d0e7d4c5..ee37e3bd61f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -219,15 +219,21 @@ private HashMap> retrieveRolesForUsers(List userO String idListString = StringUtils.join(databaseIds, ","); - qstr = "SELECT distinct g.groupalias, "; - qstr += " u.useridentifier"; - qstr += " FROM explicitgroup g,"; - qstr += " explicitgroup_authenticateduser e, "; - qstr += " authenticateduser u"; - qstr += " WHERE e.explicitgroup_id = g.id"; - qstr += " AND e.containedauthenticatedusers_id IN (" + idListString + ")"; - qstr += " AND u.id = e.containedauthenticatedusers_id"; - qstr += " ORDER by g.groupalias"; + // A *RECURSIVE* native query, that finds all the groups that the specified + // users are part of, BOTH by direct inclusion, AND via parent groups: + + qstr = "WITH RECURSIVE group_user AS ((" + + " SELECT distinct g.groupalias, g.id, u.useridentifier" + + " FROM explicitgroup g, explicitgroup_authenticateduser e, authenticateduser u" + + " WHERE e.explicitgroup_id = g.id " + + " AND u.id IN (" + idListString + ")" + + " AND u.id = e.containedauthenticatedusers_id)" + + " UNION\n" + + " SELECT p.groupalias, p.id, c.useridentifier" + + " FROM group_user c, explicitgroup p, explicitgroup_explicitgroup e" + + " WHERE e.explicitgroup_id = p.id" + + " AND e.containedexplicitgroups_id = c.id)" + + "SELECT distinct groupalias, useridentifier FROM group_user;"; //System.out.println("qstr: " + qstr); From 03dc40d8431d72a69405623f72d3cd4b110e690f Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 23 Jun 2017 11:15:27 -0400 Subject: [PATCH 58/91] removed unused method and method rename. part of review for #3614 --- .../harvard/iq/dataverse/UserServiceBean.java | 18 +----------------- .../iq/dataverse/userdata/UserListResult.java | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index ee37e3bd61f..2c799830596 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -44,20 +44,6 @@ public AuthenticatedUser save( AuthenticatedUser user ) { return user; } - /** - * Return the user information as a List of Arrays--e.g. straight from the db query - * - * @param searchTerm - * @param sortKey - * @param resultLimit - * @param offset - * @return - */ - public List getUserList(String searchTerm, String sortKey, Integer resultLimit, Integer offset){ - - return getUserListCore(searchTerm, sortKey, resultLimit, offset); - } - /** * Return the user information as a List of AuthenticatedUser objects -- easier to work with in the UI * - With Role added as a transient field @@ -496,9 +482,7 @@ public Long getUserCount(String searchTerm) { qstr += " AND prov_lookup.authenticationproviderid = prov.id"; qstr += sharedSearchClause; qstr += ";"; - - //System.out.println("getUserCount: " + qstr); - + Query nativeQuery = em.createNativeQuery(qstr); nativeQuery.setParameter("searchTerm", searchTerm + "%"); diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java index 632234d848a..99438e6fa06 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java @@ -154,7 +154,7 @@ public String getErrorMessage(){ * * @return */ - public JsonObjectBuilder asJSON(){ + public JsonObjectBuilder toJSON(){ if (userList.isEmpty()){ return getNoResultsJSON(); From 5e887ed542ae73c932a21f549afcbb76800751ef Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 23 Jun 2017 12:40:25 -0400 Subject: [PATCH 59/91] left out of last commit--needed for compile #3614 --- src/main/java/edu/harvard/iq/dataverse/api/Admin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 18c0b0e9094..3dc03d3f890 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -351,7 +351,7 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, null); - return ok(userListResult.asJSON()); + return ok(userListResult.toJSON()); } From 685e3523a5629cd6e169a599c0cfaf5a85733150 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 23 Jun 2017 12:49:21 -0400 Subject: [PATCH 60/91] remove row number for the api results #3614 --- .../iq/dataverse/authorization/users/AuthenticatedUser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 1362a462267..3d58343096a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -314,7 +314,7 @@ public JsonObjectBuilder toJson() { NullSafeJsonBuilder authenicatedUserJson = NullSafeJsonBuilder.jsonObjectBuilder(); authenicatedUserJson.add("id", this.id); - authenicatedUserJson.add("rowNum", this.rowNum); + //authenicatedUserJson.add("rowNum", this.rowNum); authenicatedUserJson.add("userIdentifier", this.userIdentifier); authenicatedUserJson.add("lastName", this.lastName); authenicatedUserJson.add("firstName", this.firstName); From 18326e4669acb620bce211ce68a854fc2ef7770e Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 23 Jun 2017 12:54:16 -0400 Subject: [PATCH 61/91] clean-up of api auth #3614 --- .../java/edu/harvard/iq/dataverse/api/Admin.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 3dc03d3f890..10f9f789570 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -319,15 +319,10 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search @QueryParam("sortKey") String sortKey ) { - boolean DEBUG_MODE = false; // DANGER HERE! Make sure it's false! - - if (DEBUG_MODE==true){ // DEBUG: use userIdentifier - - // DEBUG MODE, pass on by to the actual logic - - } else if ((session.getUser() != null)&&(session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())){ + if ((session.getUser() != null)&&(session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())){ - // Looks good, we have an authenticated superuser + // Allow in browser use of API url by an authenticated superuser + // Helpful for testing or is API call was used via AJAX request }else{ @@ -344,7 +339,7 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search return error(Response.Status.FORBIDDEN, ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.not_superuser")); } - // + } UserListMaker userListMaker = new UserListMaker(userService); From 4f6ec8e85540ddaf3b5f8a7a5fe00612f05e7d1d Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 23 Jun 2017 13:10:39 -0400 Subject: [PATCH 62/91] remove US local from number formatting #3614 --- .../harvard/iq/dataverse/dashboard/DashboardUsersPage.java | 4 +--- src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index f13aab7804e..0fb1e84b49a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -11,7 +11,6 @@ import edu.harvard.iq.dataverse.userdata.UserListResult; import java.text.NumberFormat; import java.util.List; -import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.EJB; @@ -101,9 +100,8 @@ public String getListUsersAPIPath() { * @return */ public String getUserCount() { - //return userService.getTotalUserCount(); - return NumberFormat.getNumberInstance(Locale.US).format(userService.getTotalUserCount()); + return NumberFormat.getInstance().format(userService.getTotalUserCount()); } /** diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java index c2fc87c667d..687e9e79f45 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/Pager.java @@ -5,7 +5,6 @@ */ package edu.harvard.iq.dataverse.mydata; -import com.google.gson.JsonArray; import edu.harvard.iq.dataverse.search.SearchConstants; import java.io.IOException; import static java.lang.Math.max; @@ -16,13 +15,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Locale; import javax.json.Json; import javax.json.JsonArrayBuilder; -import javax.json.JsonBuilderFactory; import javax.json.JsonObjectBuilder; -import org.primefaces.json.JSONException; -import org.primefaces.json.JSONObject; /** * @@ -345,7 +340,7 @@ public String asJSONString(){ public String addCommasToNumber(int count){ - return NumberFormat.getNumberInstance(Locale.US).format(count); + return NumberFormat.getInstance().format(count); } From 91ee5dc435b573d107f361175712895502e2d29b Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Fri, 23 Jun 2017 13:15:47 -0400 Subject: [PATCH 63/91] change asJSON to toJSON #3614 --- src/main/java/edu/harvard/iq/dataverse/DataFile.java | 4 ++-- src/main/java/edu/harvard/iq/dataverse/FileMetadata.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFile.java b/src/main/java/edu/harvard/iq/dataverse/DataFile.java index d0b511111d8..b189a434008 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFile.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFile.java @@ -831,12 +831,12 @@ public Long getPreviousDataFileId(){ return this.previousDataFileId; } - public String asPrettyJSON(){ + public String toPrettyJSON(){ return serializeAsJSON(true); } - public String asJSON(){ + public String toJSON(){ return serializeAsJSON(false); } diff --git a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java index 615f6013225..8e75b89d22f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java +++ b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java @@ -500,12 +500,12 @@ public int compare(FileMetadata o1, FileMetadata o2) { - public String asPrettyJSON(){ + public String toPrettyJSON(){ return serializeAsJSON(true); } - public String asJSON(){ + public String toJSON(){ return serializeAsJSON(false); } From 9371c46e4629fda77ab9bbf78e02ad6b9f8cc66c Mon Sep 17 00:00:00 2001 From: Michael Heppler Date: Fri, 23 Jun 2017 15:34:59 -0400 Subject: [PATCH 64/91] Minor layout clean up for Manage Users pg. [ref #3614] --- src/main/java/Bundle.properties | 5 ++--- src/main/webapp/dashboard-users-pager.xhtml | 8 ++++--- src/main/webapp/dashboard-users.xhtml | 25 +++++++-------------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 52b69a86e7f..471afddcd74 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -502,10 +502,9 @@ dashboard.card.users.message=List and manage users. dashboard.list_users.searchTerm.watermark=Search these users... dashboard.list_users.tbl_header.rowNumber=# -dashboard.list_users.tbl_header.userId=User ID +dashboard.list_users.tbl_header.userId=ID dashboard.list_users.tbl_header.userIdentifier=Username -dashboard.list_users.tbl_header.lastName=Last Name -dashboard.list_users.tbl_header.firstName=First Name +dashboard.list_users.tbl_header.name=Name dashboard.list_users.tbl_header.email=Email dashboard.list_users.tbl_header.affiliation=Affiliation dashboard.list_users.tbl_header.roles=Roles diff --git a/src/main/webapp/dashboard-users-pager.xhtml b/src/main/webapp/dashboard-users-pager.xhtml index af27fc2f82b..42a9e5898c4 100644 --- a/src/main/webapp/dashboard-users-pager.xhtml +++ b/src/main/webapp/dashboard-users-pager.xhtml @@ -9,16 +9,18 @@
-
+
+

+

-
-
    +
    +
    • diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index da8334dba39..1bf9742ec0e 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -40,45 +40,37 @@
- + - + - - + --> + - - - + - - - - - - - + + @@ -87,8 +79,7 @@ - - +

From e5db009839ac2059a6ba90268e408b96782fd959 Mon Sep 17 00:00:00 2001 From: Michael Heppler Date: Fri, 23 Jun 2017 15:40:11 -0400 Subject: [PATCH 65/91] Removed rows attribute from dataTable on Manage Users pg. [ref #3614] --- src/main/webapp/dashboard-users.xhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 1bf9742ec0e..4a713f82672 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -45,7 +45,7 @@ - + From c8999dd1bbbcad86a626695da0a8382fe053f726 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 26 Jun 2017 11:50:19 -0400 Subject: [PATCH 66/91] beginning of testing for #3614 --- .../edu/harvard/iq/dataverse/api/Admin.java | 2 +- .../edu/harvard/iq/dataverse/api/AdminIT.java | 62 +++++++++++++++++++ .../edu/harvard/iq/dataverse/api/UtilIT.java | 45 ++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 10f9f789570..bf5e74a7d96 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -89,7 +89,7 @@ public class Admin extends AbstractApiBean { DataverseSession session; public static final String listUsersPartialAPIPath = "list-users"; - public static final String listUsersFullAPIPath = "/api/v1/admin/" + listUsersPartialAPIPath; + public static final String listUsersFullAPIPath = "/api/admin/" + listUsersPartialAPIPath; @Path("settings") diff --git a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java index 4367711f5f5..2f60b9244bf 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java @@ -6,6 +6,8 @@ import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider; import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.GitHubOAuth2AP; import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.OrcidOAuth2AP; +import java.util.ArrayList; +import java.util.List; import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static javax.ws.rs.core.Response.Status.OK; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; @@ -31,6 +33,7 @@ public void testListAuthenticatedUsers() throws Exception { anon.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); Response createNonSuperuser = UtilIT.createRandomUser(); + String nonSuperuserUsername = UtilIT.getUsernameFromResponse(createNonSuperuser); String nonSuperuserApiToken = UtilIT.getApiTokenFromResponse(createNonSuperuser); @@ -57,6 +60,65 @@ public void testListAuthenticatedUsers() throws Exception { } + + @Test + public void testFilterAuthenticatedUsers() throws Exception { + + // -------------------------------------------- + // Forbidden: Try *without* an API token + // -------------------------------------------- + Response anon = UtilIT.filterAuthenticatedUsers("", null, null, null); + anon.prettyPrint(); + anon.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); + + // -------------------------------------------- + // Forbidden: Try with a regular user--*not a superuser* + // -------------------------------------------- + Response createUserResponse = UtilIT.createRandomUser(); + createUserResponse.then().assertThat().statusCode(OK.getStatusCode()); + + String nonSuperuserApiToken = UtilIT.getApiTokenFromResponse(createUserResponse); + String nonSuperUsername = UtilIT.getUsernameFromResponse(createUserResponse); + + Response filterResponseBadToken = UtilIT.filterAuthenticatedUsers(nonSuperuserApiToken, null, null, null); + filterResponseBadToken.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); + + // delete user + Response deleteNonSuperuser = UtilIT.deleteUser(nonSuperUsername); + assertEquals(200, deleteNonSuperuser.getStatusCode()); + + // -------------------------------------------- + // Make 11 random users + // -------------------------------------------- + List randomUsernames = new ArrayList(); + for (int i = 0; i < 11; i++){ + + createUserResponse = UtilIT.createRandomUser(); + createUserResponse.then().assertThat().statusCode(OK.getStatusCode()); + String newUserName = UtilIT.getUsernameFromResponse(createUserResponse); + randomUsernames.add(newUserName); + + } + + for (String aUsername : randomUsernames){ + + Response deleteUserResponse = UtilIT.deleteUser(aUsername); + assertEquals(200, deleteUserResponse.getStatusCode()); + + } + /* + String newSuperUsername = UtilIT.getUsernameFromResponse(nonSuperuser); + Response newSuperUserResponse = UtilIT.makeSuperUser(newSuperUsername); + newSuperUserResponse.then().assertThat() + .statusCode(OK.getStatusCode()); + + String superuserApiToken = UtilIT.getApiTokenFromResponse(newSuperUserResponse); +*/ + //nonSuperuser.prettyPrint(); + //nonSuperuser.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); + + } + @Test public void testConvertShibUserToBuiltin() throws Exception { 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 e2f8f99e991..737ff9dc868 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -29,6 +29,9 @@ import org.apache.commons.io.IOUtils; import static com.jayway.restassured.RestAssured.given; import static com.jayway.restassured.path.xml.XmlPath.from; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -611,6 +614,48 @@ static Response getAuthenticatedUser(String userIdentifier, String apiToken) { return response; } + /** + * Used to the test the filter Authenticated Users API endpoint + * + * Note 1 : All params are optional for endpoint to work EXCEPT superUserApiToken + * Note 2 : sortKey exists in API call but not currently used + * + * @param apiToken + * @return + */ + static Response filterAuthenticatedUsers(String superUserApiToken, + String searchTerm, + Integer selectedPage, + Integer itemsPerPage + // String sortKey + ) { + + + List queryParams = new ArrayList(); + if (searchTerm != null){ + queryParams.add("searchTerm=" + searchTerm); + } + if (selectedPage != null){ + queryParams.add("selectedPage=" + selectedPage.toString()); + } + if (itemsPerPage != null){ + queryParams.add("itemsPerPage=" + itemsPerPage.toString()); + } + + String queryString = ""; + if (queryParams.size() > 0){ + queryString = "?" + String.join("&", queryParams); + } + + + Response response = given() + .header(API_TOKEN_HTTP_HEADER, superUserApiToken) + .get("/api/admin/list-users" + queryString); + + return response; + } + + static Response getAuthProviders(String apiToken) { Response response = given() .header(API_TOKEN_HTTP_HEADER, apiToken) From 5906febe5b6c4abb61fc7af41e499f5e6f0176fc Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 26 Jun 2017 13:56:01 -0400 Subject: [PATCH 67/91] #3614, work toward tests --- src/main/java/Bundle.properties | 2 ++ .../edu/harvard/iq/dataverse/api/AdminIT.java | 31 +++++++++++++++++-- .../edu/harvard/iq/dataverse/api/UtilIT.java | 25 +++++++++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 471afddcd74..c6527d5b8f4 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -505,6 +505,8 @@ dashboard.list_users.tbl_header.rowNumber=# dashboard.list_users.tbl_header.userId=ID dashboard.list_users.tbl_header.userIdentifier=Username dashboard.list_users.tbl_header.name=Name +dashboard.list_users.tbl_header.lastName=lastName +dashboard.list_users.tbl_header.firstName=firstName dashboard.list_users.tbl_header.email=Email dashboard.list_users.tbl_header.affiliation=Affiliation dashboard.list_users.tbl_header.roles=Roles diff --git a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java index 2f60b9244bf..eec27982aa2 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java @@ -93,19 +93,46 @@ public void testFilterAuthenticatedUsers() throws Exception { List randomUsernames = new ArrayList(); for (int i = 0; i < 11; i++){ - createUserResponse = UtilIT.createRandomUser(); + createUserResponse = UtilIT.createRandomUser("rand_"); createUserResponse.then().assertThat().statusCode(OK.getStatusCode()); String newUserName = UtilIT.getUsernameFromResponse(createUserResponse); randomUsernames.add(newUserName); } + // -------------------------------------------- + // Create superuser + // -------------------------------------------- + Response createSuperuser = UtilIT.createRandomUser(); + String superuserUsername = UtilIT.getUsernameFromResponse(createSuperuser); + String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperuser); + Response toggleSuperuser = UtilIT.makeSuperUser(superuserUsername); + toggleSuperuser.then().assertThat() + .statusCode(OK.getStatusCode()); + + + // -------------------------------------------- + // Get 1,000 users + // -------------------------------------------- + Response filterReponse01 = UtilIT.filterAuthenticatedUsers(superuserApiToken, "rand_", null, 100); + //filterReponse01.then().assertThat().statusCode(OK.getStatusCode()); + //filterReponse01.prettyPrint(); + + // -------------------------------------------- + // Delete random users + // -------------------------------------------- + Response deleteUserResponse; for (String aUsername : randomUsernames){ - Response deleteUserResponse = UtilIT.deleteUser(aUsername); + deleteUserResponse = UtilIT.deleteUser(aUsername); assertEquals(200, deleteUserResponse.getStatusCode()); } + + // Delete superuser + deleteUserResponse = UtilIT.deleteUser(superuserUsername); + assertEquals(200, deleteUserResponse.getStatusCode()); + /* String newSuperUsername = UtilIT.getUsernameFromResponse(nonSuperuser); Response newSuperUserResponse = UtilIT.makeSuperUser(newSuperUsername); 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 737ff9dc868..906c2a5241b 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -60,8 +60,14 @@ static String getRestAssuredBaseUri() { return restAssuredBaseUri; } - public static Response createRandomUser() { - String randomString = getRandomUsername(); + /** + * Begin each username with a prefix + * + * @param usernamePrefix + * @return + */ + public static Response createRandomUser(String usernamePrefix) { + String randomString = getRandomUsername(usernamePrefix); logger.info("Creating random test user " + randomString); String userAsJson = getUserAsJsonString(randomString, randomString, randomString); String password = getPassword(userAsJson); @@ -72,6 +78,13 @@ public static Response createRandomUser() { return response; } + + + public static Response createRandomUser() { + + return createRandomUser("user"); + } + private static String getUserAsJsonString(String username, String firstName, String lastName) { JsonObjectBuilder builder = Json.createObjectBuilder(); builder.add(USERNAME_KEY, username); @@ -116,6 +129,14 @@ private static String getPassword(String jsonStr) { return password; } + private static String getRandomUsername(String usernamePrefix) { + + if (usernamePrefix == null){ + return getRandomUsername(); + } + return usernamePrefix + getRandomIdentifier().substring(0, 8); + } + private static String getRandomUsername() { return "user" + getRandomIdentifier().substring(0, 8); } From 6e5d197a1567fb607cdfb0fb62cc042d689ca6b6 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 26 Jun 2017 14:44:59 -0400 Subject: [PATCH 68/91] code review updates, review 'rowNum' column for list users as well as logged in superuser access for api endpoint #3614 --- src/main/java/Bundle.properties | 1 - .../harvard/iq/dataverse/UserServiceBean.java | 3 +- .../edu/harvard/iq/dataverse/api/Admin.java | 34 +++++++------------ .../users/AuthenticatedUser.java | 13 ------- src/main/webapp/dashboard-users.xhtml | 3 -- 5 files changed, 14 insertions(+), 40 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index c6527d5b8f4..35b0eb8e271 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -501,7 +501,6 @@ dashboard.card.users.manage=Manage Users dashboard.card.users.message=List and manage users. dashboard.list_users.searchTerm.watermark=Search these users... -dashboard.list_users.tbl_header.rowNumber=# dashboard.list_users.tbl_header.userId=ID dashboard.list_users.tbl_header.userIdentifier=Username dashboard.list_users.tbl_header.name=Name diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 2c799830596..00649277064 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -108,8 +108,7 @@ public List getAuthenticatedUserList(String searchTerm, Strin private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, String roles, int rowNum){ AuthenticatedUser user = new AuthenticatedUser(); - user.setRowNum(rowNum); - + user.setId(new Long((int)dbRowValues[0])); user.setUserIdentifier((String)dbRowValues[1]); user.setLastName(UserUtil.getStringOrNull(dbRowValues[2])); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index bf5e74a7d96..d72221a62f8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -319,29 +319,21 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search @QueryParam("sortKey") String sortKey ) { - if ((session.getUser() != null)&&(session.getUser().isAuthenticated()) && (session.getUser().isSuperuser())){ - - // Allow in browser use of API url by an authenticated superuser - // Helpful for testing or is API call was used via AJAX request - - }else{ - - User authUser; - try { - authUser = this.findUserOrDie(); - } catch (AbstractApiBean.WrappedResponse ex) { - return error(Response.Status.FORBIDDEN, - ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.invalid_apikey") - ); - } - - if (!authUser.isSuperuser()){ - return error(Response.Status.FORBIDDEN, - ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.not_superuser")); - } - + User authUser; + try { + authUser = this.findUserOrDie(); + } catch (AbstractApiBean.WrappedResponse ex) { + return error(Response.Status.FORBIDDEN, + ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.invalid_apikey") + ); + } + + if (!authUser.isSuperuser()){ + return error(Response.Status.FORBIDDEN, + ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.not_superuser")); } + UserListMaker userListMaker = new UserListMaker(userService); UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, null); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 3d58343096a..60147e28e9b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -149,18 +149,6 @@ public String getRoles() { public void setRoles(String roles) { this.roles = roles; } - - //For User List Admin dashboard - @Transient - private Integer rowNum; - - public Integer getRowNum() { - return rowNum; - } - - public void setRowNum(Integer rowNum) { - this.rowNum = rowNum; - } //For User List Admin dashboard - AuthenticatedProviderId @Transient @@ -314,7 +302,6 @@ public JsonObjectBuilder toJson() { NullSafeJsonBuilder authenicatedUserJson = NullSafeJsonBuilder.jsonObjectBuilder(); authenicatedUserJson.add("id", this.id); - //authenicatedUserJson.add("rowNum", this.rowNum); authenicatedUserJson.add("userIdentifier", this.userIdentifier); authenicatedUserJson.add("lastName", this.lastName); authenicatedUserJson.add("firstName", this.firstName); diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 4a713f82672..a70b4fa40eb 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -46,9 +46,6 @@ - From 21f1ba1d48306990c89272219db312ead83ef500 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 26 Jun 2017 16:20:19 -0400 Subject: [PATCH 69/91] work for user list tests #3614 --- .../edu/harvard/iq/dataverse/api/Admin.java | 4 +- .../iq/dataverse/userdata/UserListMaker.java | 3 +- .../edu/harvard/iq/dataverse/api/AdminIT.java | 150 +++++++++++++++--- .../edu/harvard/iq/dataverse/api/UtilIT.java | 16 +- 4 files changed, 146 insertions(+), 27 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index d72221a62f8..70ede8e32aa 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -318,7 +318,7 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search @QueryParam("numDisplay") Integer itemsPerPage, @QueryParam("sortKey") String sortKey ) { - + /* User authUser; try { authUser = this.findUserOrDie(); @@ -333,7 +333,7 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.not_superuser")); } - + */ UserListMaker userListMaker = new UserListMaker(userService); UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, null); diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java index 050a06c8ec7..f942a52291c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListMaker.java @@ -28,6 +28,7 @@ public class UserListMaker { public String errorMessage = null; public static final int ITEMS_PER_PAGE = 25; + public static final int MIN_ITEMS_PER_PAGE = 1; public static final int DEFAULT_OFFSET = 0; @@ -76,7 +77,7 @@ public UserListResult runUserSearch(String searchTerm, Integer itemsPerPage, Int } // Initialize itemsPerPage - if ((itemsPerPage == null) || (itemsPerPage < 10)){ + if ((itemsPerPage == null) || (itemsPerPage < MIN_ITEMS_PER_PAGE)){ itemsPerPage = ITEMS_PER_PAGE; } diff --git a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java index eec27982aa2..f7686d90a63 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/AdminIT.java @@ -3,6 +3,7 @@ import com.jayway.restassured.RestAssured; import com.jayway.restassured.path.json.JsonPath; import com.jayway.restassured.response.Response; +import static edu.harvard.iq.dataverse.api.UtilIT.getRandomString; import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider; import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.GitHubOAuth2AP; import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.OrcidOAuth2AP; @@ -14,6 +15,7 @@ import org.junit.Test; import org.junit.BeforeClass; import java.util.UUID; +import javax.validation.constraints.AssertTrue; import static javax.ws.rs.core.Response.Status.CREATED; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.notNullValue; @@ -40,7 +42,7 @@ public void testListAuthenticatedUsers() throws Exception { Response nonSuperuser = UtilIT.listAuthenticatedUsers(nonSuperuserApiToken); nonSuperuser.prettyPrint(); nonSuperuser.then().assertThat().statusCode(FORBIDDEN.getStatusCode()); - + Response createSuperuser = UtilIT.createRandomUser(); String superuserUsername = UtilIT.getUsernameFromResponse(createSuperuser); String superuserApiToken = UtilIT.getApiTokenFromResponse(createSuperuser); @@ -62,7 +64,7 @@ public void testListAuthenticatedUsers() throws Exception { @Test - public void testFilterAuthenticatedUsers() throws Exception { + public void testFilterAuthenticatedUsersForbidden() throws Exception { // -------------------------------------------- // Forbidden: Try *without* an API token @@ -86,14 +88,26 @@ public void testFilterAuthenticatedUsers() throws Exception { // delete user Response deleteNonSuperuser = UtilIT.deleteUser(nonSuperUsername); assertEquals(200, deleteNonSuperuser.getStatusCode()); + } + + /** + * Run multiple test against API endpoint to search authenticated users + * @throws Exception + */ + @Test + public void testFilterAuthenticatedUsers() throws Exception { + + Response createUserResponse; // -------------------------------------------- // Make 11 random users // -------------------------------------------- - List randomUsernames = new ArrayList(); + String randUserNamePrefix = "r" + UtilIT.getRandomString(4) + "_"; + + List randomUsernames = new ArrayList(); for (int i = 0; i < 11; i++){ - createUserResponse = UtilIT.createRandomUser("rand_"); + createUserResponse = UtilIT.createRandomUser(randUserNamePrefix); createUserResponse.then().assertThat().statusCode(OK.getStatusCode()); String newUserName = UtilIT.getUsernameFromResponse(createUserResponse); randomUsernames.add(newUserName); @@ -112,12 +126,118 @@ public void testFilterAuthenticatedUsers() throws Exception { // -------------------------------------------- - // Get 1,000 users + // Search for the 11 new users and verify results + // -------------------------------------------- + Response filterReponse01 = UtilIT.filterAuthenticatedUsers(superuserApiToken, randUserNamePrefix, null, 100); + filterReponse01.then().assertThat().statusCode(OK.getStatusCode()); + filterReponse01.prettyPrint(); + + int numResults = 11; + filterReponse01.then().assertThat() + .body("data.userCount", equalTo(numResults)) + .body("data.selectedPage", equalTo(1)) + .body("data.pagination.pageCount", equalTo(1)) + .body("data.pagination.numResults", equalTo(numResults)); + + String userIdentifer; + for (int i=0; i < numResults; i++){ + userIdentifer = JsonPath.from(filterReponse01.getBody().asString()).getString("data.users[" + i + "].userIdentifier"); + assertEquals(randomUsernames.contains(userIdentifer), true); + } + + List userList1 = JsonPath.from(filterReponse01.body().asString()).getList("data.users"); + assertEquals(userList1.size(), numResults); + + // -------------------------------------------- + // Search for the 11 new users, but only return 5 per page + // -------------------------------------------- + int numUsersReturned = 5; + Response filterReponse02 = UtilIT.filterAuthenticatedUsers(superuserApiToken, randUserNamePrefix, 1, numUsersReturned); + filterReponse02.then().assertThat().statusCode(OK.getStatusCode()); + filterReponse02.prettyPrint(); + + filterReponse02.then().assertThat() + .body("data.userCount", equalTo(numResults)) + .body("data.selectedPage", equalTo(1)) + .body("data.pagination.docsPerPage", equalTo(numUsersReturned)) + .body("data.pagination.pageCount", equalTo(3)) + .body("data.pagination.numResults", equalTo(numResults)); + + String userIdentifer2; + for (int i=0; i < numUsersReturned; i++){ + userIdentifer2 = JsonPath.from(filterReponse02.getBody().asString()).getString("data.users[" + i + "].userIdentifier"); + assertEquals(randomUsernames.contains(userIdentifer2), true); + } + + List userList2 = JsonPath.from(filterReponse02.body().asString()).getList("data.users"); + assertEquals(userList2.size(), numUsersReturned); + + + // -------------------------------------------- + // Search for the 11 new users, return 5 per page, and start on NON-EXISTENT 4th page -- should revert to 1st page + // -------------------------------------------- + Response filterReponse02a = UtilIT.filterAuthenticatedUsers(superuserApiToken, randUserNamePrefix, 4, numUsersReturned); + filterReponse02a.then().assertThat().statusCode(OK.getStatusCode()); + filterReponse02a.prettyPrint(); + + filterReponse02a.then().assertThat() + .body("data.userCount", equalTo(numResults)) + .body("data.selectedPage", equalTo(1)) + .body("data.pagination.docsPerPage", equalTo(numUsersReturned)) + .body("data.pagination.pageCount", equalTo(3)) + .body("data.pagination.numResults", equalTo(numResults)); + + List userList2a = JsonPath.from(filterReponse02a.body().asString()).getList("data.users"); + assertEquals(userList2a.size(), numUsersReturned); + + // -------------------------------------------- + // Search for the 11 new users, return 5 per page, start on 3rd page + // -------------------------------------------- + Response filterReponse03 = UtilIT.filterAuthenticatedUsers(superuserApiToken, randUserNamePrefix, 3, 5); + filterReponse03.then().assertThat().statusCode(OK.getStatusCode()); + filterReponse03.prettyPrint(); + + filterReponse03.then().assertThat() + .body("data.userCount", equalTo(numResults)) + .body("data.selectedPage", equalTo(3)) + .body("data.pagination.docsPerPage", equalTo(5)) + .body("data.pagination.hasNextPageNumber", equalTo(false)) + .body("data.pagination.pageCount", equalTo(3)) + .body("data.pagination.numResults", equalTo(numResults)); + + List userList3 = JsonPath.from(filterReponse03.body().asString()).getList("data.users"); + assertEquals(userList3.size(), 1); + + // -------------------------------------------- + // Run search that returns no users + // -------------------------------------------- + Response filterReponse04 = UtilIT.filterAuthenticatedUsers(superuserApiToken, "zzz" + randUserNamePrefix, 1, 50); + filterReponse04.then().assertThat().statusCode(OK.getStatusCode()); + filterReponse04.prettyPrint(); + + filterReponse04.then().assertThat() + .body("data.userCount", equalTo(0)) + .body("data.selectedPage", equalTo(1)); + + List userList4 = JsonPath.from(filterReponse04.body().asString()).getList("data.users"); + assertEquals(userList4.size(), 0); + + // -------------------------------------------- - Response filterReponse01 = UtilIT.filterAuthenticatedUsers(superuserApiToken, "rand_", null, 100); - //filterReponse01.then().assertThat().statusCode(OK.getStatusCode()); - //filterReponse01.prettyPrint(); + // Run search that returns 1 user + // -------------------------------------------- + String singleUsername = randomUsernames.get(0); + Response filterReponse05 = UtilIT.filterAuthenticatedUsers(superuserApiToken, singleUsername, 1, 50); + filterReponse05.then().assertThat().statusCode(OK.getStatusCode()); + filterReponse05.prettyPrint(); + filterReponse05.then().assertThat() + .body("data.userCount", equalTo(1)) + .body("data.selectedPage", equalTo(1)); + + List userList5 = JsonPath.from(filterReponse05.body().asString()).getList("data.users"); + assertEquals(userList5.size(), 1); + // -------------------------------------------- // Delete random users // -------------------------------------------- @@ -129,20 +249,12 @@ public void testFilterAuthenticatedUsers() throws Exception { } + // -------------------------------------------- // Delete superuser + // -------------------------------------------- deleteUserResponse = UtilIT.deleteUser(superuserUsername); assertEquals(200, deleteUserResponse.getStatusCode()); - - /* - String newSuperUsername = UtilIT.getUsernameFromResponse(nonSuperuser); - Response newSuperUserResponse = UtilIT.makeSuperUser(newSuperUsername); - newSuperUserResponse.then().assertThat() - .statusCode(OK.getStatusCode()); - - String superuserApiToken = UtilIT.getApiTokenFromResponse(newSuperUserResponse); -*/ - //nonSuperuser.prettyPrint(); - //nonSuperuser.then().assertThat().statusCode(FORBIDDEN.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 906c2a5241b..6470dcbc0ff 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -137,6 +137,13 @@ private static String getRandomUsername(String usernamePrefix) { return usernamePrefix + getRandomIdentifier().substring(0, 8); } + public static String getRandomString(int length) { + if (length < 0){ + length = 3; + } + return getRandomIdentifier().substring(0, length+1); + } + private static String getRandomUsername() { return "user" + getRandomIdentifier().substring(0, 8); } @@ -647,7 +654,7 @@ static Response getAuthenticatedUser(String userIdentifier, String apiToken) { static Response filterAuthenticatedUsers(String superUserApiToken, String searchTerm, Integer selectedPage, - Integer itemsPerPage + Integer numDisplay // String sortKey ) { @@ -659,16 +666,15 @@ static Response filterAuthenticatedUsers(String superUserApiToken, if (selectedPage != null){ queryParams.add("selectedPage=" + selectedPage.toString()); } - if (itemsPerPage != null){ - queryParams.add("itemsPerPage=" + itemsPerPage.toString()); + if (numDisplay != null){ + queryParams.add("numDisplay=" + numDisplay.toString()); } String queryString = ""; if (queryParams.size() > 0){ queryString = "?" + String.join("&", queryParams); } - - + Response response = given() .header(API_TOKEN_HTTP_HEADER, superUserApiToken) .get("/api/admin/list-users" + queryString); From bd5b72385a57e88a9c2818b921a1578eab998cab Mon Sep 17 00:00:00 2001 From: Leonid Andreev Date: Mon, 26 Jun 2017 18:59:36 -0400 Subject: [PATCH 70/91] Per code review with Gustavo, the current user admin user viewing the dashboard should not be allowed to toggle the superuser status for him- or herself. --- src/main/webapp/dashboard-users.xhtml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index a70b4fa40eb..3d3e761a813 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -71,9 +71,8 @@ - - - + + From 902daeaa29025329df8ce246cf5041d9eee97de3 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Jun 2017 09:26:32 -0400 Subject: [PATCH 71/91] explain that Glassfish must be run in English locale #2620 --- doc/sphinx-guides/source/installation/prerequisites.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/sphinx-guides/source/installation/prerequisites.rst b/doc/sphinx-guides/source/installation/prerequisites.rst index a570e5ab84e..4288d5fb2d0 100644 --- a/doc/sphinx-guides/source/installation/prerequisites.rst +++ b/doc/sphinx-guides/source/installation/prerequisites.rst @@ -78,6 +78,8 @@ Adjust this :download:`Glassfish init script <../_static/installation/files/etc/ It is not necessary to have Glassfish running before you execute the Dataverse installation script because it will start Glassfish for you. +Please note that you must run Glassfish in an English locale. If you are using something like ``LANG=de_DE.UTF-8`` ingest of tabular data will fail with "RoundRoutines:decimal separator no in right place". + PostgreSQL ---------- From 969f0a52607cdae6de8509830e261ffdb2946b6e Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 27 Jun 2017 12:30:30 -0400 Subject: [PATCH 72/91] #3614 switch count to native query. document attempt at setParameter for list of identifiers --- .../harvard/iq/dataverse/UserServiceBean.java | 42 +++++++++++-------- .../edu/harvard/iq/dataverse/api/Admin.java | 4 +- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 00649277064..a34d0599728 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -150,16 +150,27 @@ private HashMap> retrieveRolesForUsers(List userO return null; } - // Add '@' to each identifier and delimit the list by "," + // ------------------------------------------------- + // Prepare a string to use within the SQL "a.assigneeidentifier IN (....)" clause + // + // Note: This is not ideal but .setParameter was failing with attempts using: // + // Collection, List, String[] + // + // This appears to be due to the JDBC driver or Postgres. In this case SQL + // injection isn't possible b/c the list of assigneeidentifier strings comes + // from a previous query + // + // Add '@' to each identifier and delimit the list by "," + // ------------------------------------------------- String identifierListString = userIdentifierList.stream() .filter(x -> !Strings.isNullOrEmpty(x)) .map(x -> "'@" + x + "'") .collect(Collectors.joining(", ")); - - //System.out.println("identifierListString: " + identifierListString); - - + + // ------------------------------------------------- + // Create/Run the query to find directly assigned roles + // ------------------------------------------------- String qstr = "SELECT distinct a.assigneeidentifier,"; qstr += " d.name"; qstr += " FROM roleassignment a,"; @@ -168,8 +179,6 @@ private HashMap> retrieveRolesForUsers(List userO qstr += " AND a.assigneeidentifier IN (" + identifierListString + ")"; qstr += " ORDER by a.assigneeidentifier, d.name;"; - //System.out.println("qstr: " + qstr); - Query nativeQuery = em.createNativeQuery(qstr); List dbRoleResults = nativeQuery.getResultList(); @@ -432,16 +441,15 @@ private String getSharedSearchClause(){ * @return */ public Long getSuperUserCount() { - - String qstr = "SELECT count(id)"; - qstr += " FROM authenticateduser"; - qstr += " WHERE superuser = true"; - qstr += ";"; - - Query nativeQuery = em.createNativeQuery(qstr); - - return (Long)nativeQuery.getSingleResult(); - + + String qstr = "SELECT count(au)"; + qstr += " FROM AuthenticatedUser au"; + qstr += " WHERE au.superuser = :superuserTrue"; + + Query query = em.createQuery(qstr); + query.setParameter("superuserTrue", true); + + return (Long)query.getSingleResult(); } /** diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 70ede8e32aa..d72221a62f8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -318,7 +318,7 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search @QueryParam("numDisplay") Integer itemsPerPage, @QueryParam("sortKey") String sortKey ) { - /* + User authUser; try { authUser = this.findUserOrDie(); @@ -333,7 +333,7 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search ResourceBundle.getBundle("Bundle").getString("dashboard.list_users.api.auth.not_superuser")); } - */ + UserListMaker userListMaker = new UserListMaker(userService); UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, null); From 9356858ddc6f18dd418c7cda2969e7cd3688502b Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Jun 2017 13:06:23 -0400 Subject: [PATCH 73/91] typo #3964 --- doc/sphinx-guides/source/installation/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index 1c193275534..ea8cf0a3296 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -315,7 +315,7 @@ If you are not fronting Glassfish with Apache you'll need to prevent Glassfish f Putting Your Dataverse Installation on the Map at dataverse.org +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Congratulations! You've gone live! It's time to announce your new data respository to the world! You are also welcome to contact support@dataverse.org to have the Dataverse team add your installation to the map at http://dataverse.org . Thank you for installing Datavese! +Congratulations! You've gone live! It's time to announce your new data respository to the world! You are also welcome to contact support@dataverse.org to have the Dataverse team add your installation to the map at http://dataverse.org . Thank you for installing Dataverse! Administration of Your Dataverse Installation +++++++++++++++++++++++++++++++++++++++++++++ From fce05c81fda26cd10789b6f35e823dda2546e63c Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Jun 2017 13:15:53 -0400 Subject: [PATCH 74/91] document :ZipDownloadLimit #3857 --- doc/sphinx-guides/source/installation/config.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index ea8cf0a3296..1e9140463eb 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -687,6 +687,13 @@ Notes: ``curl -X PUT -d 2147483648 http://localhost:8080/api/admin/settings/:MaxFileUploadSizeInBytes`` +:ZipDownloadLimit ++++++++++++++++++ + +For performance reasons, Dataverse will only create zip files on the fly up to 100 MB but the limit can be increased. Here's an example of raising the limit to 1 GB: + +``curl -X PUT -d 1000000000 http://localhost:8080/api/admin/settings/:ZipDownloadLimit`` + :TabularIngestSizeLimit +++++++++++++++++++++++ From 22e62088166544463cba29f5ce733685b5832905 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Jun 2017 13:29:58 -0400 Subject: [PATCH 75/91] fix description of :CloudEnvironmentName #3847 --- doc/sphinx-guides/source/installation/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index 1e9140463eb..4cde91e940a 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -876,7 +876,7 @@ Set the base URL for the "Compute" button for a dataset. :CloudEnvironmentName +++++++++++++++++++++ -Set the base URL for the "Compute" button for a dataset. +Set the name of the cloud environment you've integrated with your Dataverse installation. ``curl -X PUT -d 'Massachusetts Open Cloud (MOC)' http://localhost:8080/api/admin/settings/:CloudEnvironmentName`` From c4f34df9e509ed0aa515cbe21e241263486e97c7 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Jun 2017 13:34:54 -0400 Subject: [PATCH 76/91] add note about showAttributeValues #3649 --- .../_static/installation/files/etc/shibboleth/shibboleth2.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/sphinx-guides/source/_static/installation/files/etc/shibboleth/shibboleth2.xml b/doc/sphinx-guides/source/_static/installation/files/etc/shibboleth/shibboleth2.xml index dc79aebde38..8aa95b1c10c 100644 --- a/doc/sphinx-guides/source/_static/installation/files/etc/shibboleth/shibboleth2.xml +++ b/doc/sphinx-guides/source/_static/installation/files/etc/shibboleth/shibboleth2.xml @@ -41,6 +41,7 @@ https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPConfiguration + From 375e4b88282ab8efc032da99fd8f26ecb56e9a8c Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Jun 2017 13:51:48 -0400 Subject: [PATCH 77/91] document :StatusMessageText #2944 --- doc/sphinx-guides/source/installation/config.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index 4cde91e940a..6c6e1f895c9 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -677,6 +677,15 @@ For dynamically adding information to the top of every page. For example, "For t ``curl -X PUT -d "For testing only..." http://localhost:8080/api/admin/settings/:StatusMessageHeader`` +You can make the text clickable and include an additional message in a pop up by setting ``:StatusMessageText``. + +:StatusMessageText +++++++++++++++++++ + +After you've set ``:StatusMessageHeader`` you can also make it clickable to have it include text if a popup with this: + +``curl -X PUT -d "This appears in a popup." http://localhost:8080/api/admin/settings/:StatusMessageText`` + :MaxFileUploadSizeInBytes +++++++++++++++++++++++++ From 7a25089fa551815dd522cdb4730d46186bda9f8a Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Tue, 27 Jun 2017 15:43:14 -0400 Subject: [PATCH 78/91] remove mod time. #3614 --- .../java/edu/harvard/iq/dataverse/UserServiceBean.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index 5860dd1c7de..a626190e7bd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -115,7 +115,7 @@ public List getAuthenticatedUserList(String searchTerm, Strin private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, String roles, int rowNum){ AuthenticatedUser user = new AuthenticatedUser(); - + user.setId(new Long((int)dbRowValues[0])); user.setUserIdentifier((String)dbRowValues[1]); user.setLastName(UserUtil.getStringOrNull(dbRowValues[2])); @@ -124,8 +124,8 @@ private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, user.setAffiliation(UserUtil.getStringOrNull(dbRowValues[5])); user.setSuperuser((Boolean)(dbRowValues[6])); user.setPosition(UserUtil.getStringOrNull(dbRowValues[7])); - user.setAuthProviderId(UserUtil.getStringOrNull(dbRowValues[9])); - user.setAuthProviderFactoryAlias(UserUtil.getStringOrNull(dbRowValues[10])); + user.setAuthProviderId(UserUtil.getStringOrNull(dbRowValues[8])); + user.setAuthProviderFactoryAlias(UserUtil.getStringOrNull(dbRowValues[9])); user.setRoles(roles); return user; @@ -400,7 +400,7 @@ private List getUserListCore(String searchTerm, String sortKey, Intege String qstr = "SELECT u.id, u.useridentifier,"; qstr += " u.lastname, u.firstname, u.email,"; qstr += " u.affiliation, u.superuser,"; - qstr += " u.position, u.modificationtime,"; + qstr += " u.position,"; qstr += " prov.id, prov.factoryalias"; qstr += " FROM authenticateduser u,"; qstr += " authenticateduserlookup prov_lookup,"; From bf6994c484daa2d3a51bbe79d77736d9e501874f Mon Sep 17 00:00:00 2001 From: Derek Murphy Date: Tue, 27 Jun 2017 17:32:17 -0400 Subject: [PATCH 79/91] Proofread of new text #2620 Added a comma and a couple new words. Looks good! --- doc/sphinx-guides/source/installation/prerequisites.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/installation/prerequisites.rst b/doc/sphinx-guides/source/installation/prerequisites.rst index 4288d5fb2d0..1829c6396e8 100644 --- a/doc/sphinx-guides/source/installation/prerequisites.rst +++ b/doc/sphinx-guides/source/installation/prerequisites.rst @@ -78,7 +78,7 @@ Adjust this :download:`Glassfish init script <../_static/installation/files/etc/ It is not necessary to have Glassfish running before you execute the Dataverse installation script because it will start Glassfish for you. -Please note that you must run Glassfish in an English locale. If you are using something like ``LANG=de_DE.UTF-8`` ingest of tabular data will fail with "RoundRoutines:decimal separator no in right place". +Please note that you must run Glassfish in an English locale. If you are using something like ``LANG=de_DE.UTF-8``, ingest of tabular data will fail with the message "RoundRoutines:decimal separator no in right place". PostgreSQL ---------- From 66c30c7f17b3a03575ab7a69e0c017ba0dde81a6 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 27 Jun 2017 21:34:00 -0400 Subject: [PATCH 80/91] An API token is sometimes called a key #1293 --- doc/sphinx-guides/source/api/intro.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx-guides/source/api/intro.rst b/doc/sphinx-guides/source/api/intro.rst index d2f6c4e2487..a9543dff0a5 100755 --- a/doc/sphinx-guides/source/api/intro.rst +++ b/doc/sphinx-guides/source/api/intro.rst @@ -21,7 +21,7 @@ We use the term "native" to mean that the API is not based on any standard. For Authentication -------------- -Most Dataverse APIs require the use of an API token. Instructions for getting a token are described in the :doc:`/user/account` section of the User Guide. +Most Dataverse APIs require the use of an API token. (In code we sometimes call it a "key" because it's shorter.) Instructions for getting a token are described in the :doc:`/user/account` section of the User Guide. There are two ways to pass your API token to Dataverse APIs. The preferred method is to send the token in the ``X-Dataverse-key`` HTTP header, as in the following curl example:: From f1166a7050acaaacb3bbe6e2cc445129f3a2447c Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Wed, 28 Jun 2017 11:50:32 -0400 Subject: [PATCH 81/91] update to saving the superuser. retrieve the persistent AuthenticatedUser and save that. #3614 --- .../harvard/iq/dataverse/UserServiceBean.java | 10 ++++- .../users/AuthenticatedUser.java | 19 +++++++-- .../dashboard/DashboardUsersPage.java | 39 +++++++++++++------ src/main/webapp/dashboard-users.xhtml | 8 ++-- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java index a626190e7bd..dd3ce4e5633 100644 --- a/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java @@ -124,8 +124,13 @@ private AuthenticatedUser createAuthenticatedUserForView (Object[] dbRowValues, user.setAffiliation(UserUtil.getStringOrNull(dbRowValues[5])); user.setSuperuser((Boolean)(dbRowValues[6])); user.setPosition(UserUtil.getStringOrNull(dbRowValues[7])); - user.setAuthProviderId(UserUtil.getStringOrNull(dbRowValues[8])); - user.setAuthProviderFactoryAlias(UserUtil.getStringOrNull(dbRowValues[9])); + + user.setCreatedTime(UserUtil.getTimestampOrNull(dbRowValues[8])); + user.setLastLoginTime(UserUtil.getTimestampOrNull(dbRowValues[9])); + user.setLastApiUseTime(UserUtil.getTimestampOrNull(dbRowValues[10])); + + user.setAuthProviderId(UserUtil.getStringOrNull(dbRowValues[11])); + user.setAuthProviderFactoryAlias(UserUtil.getStringOrNull(dbRowValues[12])); user.setRoles(roles); return user; @@ -401,6 +406,7 @@ private List getUserListCore(String searchTerm, String sortKey, Intege qstr += " u.lastname, u.firstname, u.email,"; qstr += " u.affiliation, u.superuser,"; qstr += " u.position,"; + qstr += " u.createdtime, u.lastlogintime, u.lastapiusetime, "; qstr += " prov.id, prov.factoryalias"; qstr += " FROM authenticateduser u,"; qstr += " authenticateduserlookup prov_lookup,"; diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 35aefc3070c..0cb75d7dae6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -4,16 +4,13 @@ import edu.harvard.iq.dataverse.ValidateEmail; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserLookup; -import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider; import edu.harvard.iq.dataverse.userdata.UserUtil; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.io.Serializable; import java.sql.Timestamp; -import java.util.Date; import java.util.List; import java.util.Objects; -import javax.json.Json; import javax.json.JsonObjectBuilder; import javax.persistence.CascadeType; import javax.persistence.Column; @@ -29,6 +26,15 @@ import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.NotBlank; +/** + * When adding an attribute to this class, be sure to update the following: + * + * (1) AuthenticatedUser.toJSON() - within this class (REQUIRED) + * (2) UserServiceBean.getUserListCore() - native SQL query + * (3) UserServiceBean.createAuthenticatedUserForView() - add values to a detached AuthenticatedUser object + * + * @author rmp553 + */ @NamedQueries({ @NamedQuery( name="AuthenticatedUser.findAll", query="select au from AuthenticatedUser au"), @@ -313,7 +319,12 @@ public JsonObjectBuilder toJson() { authenicatedUserJson.add("affiliation", UserUtil.getStringOrNull(this.affiliation)); authenicatedUserJson.add("isSuperuser", this.superuser); authenicatedUserJson.add("position", UserUtil.getStringOrNull(this.position)); - authenicatedUserJson.add("authenticationProvider", this.authProviderFactoryAlias); + + authenicatedUserJson.add("createdTime", UserUtil.getTimestampStringOrNull(this.createdTime)); + authenicatedUserJson.add("lastLoginTime", UserUtil.getTimestampStringOrNull(this.lastLoginTime)); + authenicatedUserJson.add("lastApiUseTime", UserUtil.getTimestampStringOrNull(this.lastApiUseTime)); + + authenicatedUserJson.add("authenticationProvider", this.authProviderFactoryAlias); authenicatedUserJson.add("roles", UserUtil.getStringOrNull(this.roles)); return authenicatedUserJson; diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 0fb1e84b49a..9575f150c32 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -155,32 +155,47 @@ public void setSearchTerm(String searchTerm) { popup, then finalizing the toggled value. */ - AuthenticatedUser selectedUser = null; + AuthenticatedUser selectedUserDetached = null; // Note: This is NOT the persisted object!!!! Don't try to save it, etc. + AuthenticatedUser selectedUserPersistent = null; // This is called on the fly and updated - public void setSelectedUser(AuthenticatedUser user) { - this.selectedUser = user; + public void setSelectedUserDetached(AuthenticatedUser user) { + this.selectedUserDetached = user; } - public AuthenticatedUser getSelectedUser() { - return this.selectedUser; + public AuthenticatedUser getSelectedUserDetached() { + return this.selectedUserDetached; } public void setUserToToggleSuperuserStatus(AuthenticatedUser user) { logger.info("selecting user "+user.getIdentifier()); - selectedUser = user; + + selectedUserDetached = user; } + public void saveSuperuserStatus(){ - logger.info("Toggling user's "+selectedUser.getIdentifier()+" superuser status; (current status: "+selectedUser.isSuperuser()+")"); - logger.info("Attempting to save user "+selectedUser.getIdentifier()); - authenticationService.update(selectedUser); + + // Retrieve the persistent version for saving to db + logger.info("Get persisent AuthenticatedUser for id: " + selectedUserDetached.getId()); + selectedUserPersistent = userService.find(selectedUserDetached.getId()); + + if (selectedUserPersistent != null){ + logger.info("Toggling user's "+selectedUserDetached.getIdentifier()+" superuser status; (current status: "+selectedUserDetached.isSuperuser()+")"); + logger.info("Attempting to save user "+selectedUserDetached.getIdentifier()); + + logger.info("selectedUserPersistent info: "+selectedUserPersistent.getId() + " set to: " + selectedUserDetached.isSuperuser()); + selectedUserPersistent.setSuperuser(selectedUserDetached.isSuperuser()); + selectedUserPersistent = authenticationService.update(selectedUserPersistent); + }else{ + logger.warning("selectedUserPersistent is null. AuthenticatedUser not found for id: " + selectedUserDetached.getId()); + } } public void cancelSuperuserStatusChange(){ - logger.info("unToggling user's "+selectedUser.getIdentifier()+" superuser status; (current status: "+selectedUser.isSuperuser()+")"); - selectedUser.setSuperuser(!selectedUser.isSuperuser()); - + logger.info("unToggling user's "+selectedUserDetached.getIdentifier()+" superuser status; (current status: "+selectedUserDetached.isSuperuser()+")"); + selectedUserDetached.setSuperuser(!selectedUserDetached.isSuperuser()); + selectedUserPersistent = null; } diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 3d3e761a813..1241b2ddd4c 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -79,11 +79,11 @@

- - + + - - + +

From 2bcef31fd185d7001a7e23d7be078551d1904416 Mon Sep 17 00:00:00 2001 From: Michael Heppler Date: Wed, 28 Jun 2017 12:27:49 -0400 Subject: [PATCH 82/91] Added conditional style, icon for Superuser to Manage Users pg. [ref #3614 #3612] --- src/main/webapp/dashboard-users.xhtml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 1241b2ddd4c..0bc4b3d6def 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -50,12 +50,13 @@ - + + - + @@ -64,10 +65,10 @@ - + - + From d24fa0a4370fcfd8f1493911cdbb27aaaff0419f Mon Sep 17 00:00:00 2001 From: Leonid Andreev Date: Wed, 28 Jun 2017 20:43:39 -0400 Subject: [PATCH 83/91] Per Gustavo's code review request, added commands for granting and revoking the superuser status. The commands are used by the dashboard user list page. But not the admin API. Please ask Gustavo if you have any questions about this change. Hopefully this is the last commit for #3614-#3612. --- .../dashboard/DashboardUsersPage.java | 40 ++++++++++---- .../impl/GrantSuperuserStatusCommand.java | 51 ++++++++++++++++++ .../impl/RevokeSuperuserStatusCommand.java | 52 +++++++++++++++++++ 3 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 9575f150c32..429ccff810a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -1,11 +1,15 @@ package edu.harvard.iq.dataverse.dashboard; +import edu.harvard.iq.dataverse.DataverseRequestServiceBean; import edu.harvard.iq.dataverse.DataverseSession; +import edu.harvard.iq.dataverse.EjbDataverseEngine; import edu.harvard.iq.dataverse.PermissionsWrapper; import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.api.Admin; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.engine.command.impl.GrantSuperuserStatusCommand; +import edu.harvard.iq.dataverse.engine.command.impl.RevokeSuperuserStatusCommand; import edu.harvard.iq.dataverse.mydata.Pager; import edu.harvard.iq.dataverse.userdata.UserListMaker; import edu.harvard.iq.dataverse.userdata.UserListResult; @@ -30,6 +34,10 @@ public class DashboardUsersPage implements java.io.Serializable { DataverseSession session; @Inject PermissionsWrapper permissionsWrapper; + @EJB + EjbDataverseEngine commandEngine; + @EJB + DataverseRequestServiceBean dvRequestService; private static final Logger logger = Logger.getLogger(DashboardUsersPage.class.getCanonicalName()); @@ -173,23 +181,35 @@ public void setUserToToggleSuperuserStatus(AuthenticatedUser user) { selectedUserDetached = user; } - public void saveSuperuserStatus(){ - + public void saveSuperuserStatus() { + // Retrieve the persistent version for saving to db logger.info("Get persisent AuthenticatedUser for id: " + selectedUserDetached.getId()); selectedUserPersistent = userService.find(selectedUserDetached.getId()); - - if (selectedUserPersistent != null){ - logger.info("Toggling user's "+selectedUserDetached.getIdentifier()+" superuser status; (current status: "+selectedUserDetached.isSuperuser()+")"); - logger.info("Attempting to save user "+selectedUserDetached.getIdentifier()); - logger.info("selectedUserPersistent info: "+selectedUserPersistent.getId() + " set to: " + selectedUserDetached.isSuperuser()); + if (selectedUserPersistent != null) { + logger.info("Toggling user's " + selectedUserDetached.getIdentifier() + " superuser status; (current status: " + selectedUserDetached.isSuperuser() + ")"); + logger.info("Attempting to save user " + selectedUserDetached.getIdentifier()); + + logger.info("selectedUserPersistent info: " + selectedUserPersistent.getId() + " set to: " + selectedUserDetached.isSuperuser()); selectedUserPersistent.setSuperuser(selectedUserDetached.isSuperuser()); - selectedUserPersistent = authenticationService.update(selectedUserPersistent); - }else{ + + // Using the new commands for granting and revoking the superuser status: + try { + if (!selectedUserPersistent.isSuperuser()) { + // We are revoking the status: + commandEngine.submit(new RevokeSuperuserStatusCommand(selectedUserPersistent, dvRequestService.getDataverseRequest())); + } else { + // granting the status: + commandEngine.submit(new GrantSuperuserStatusCommand(selectedUserPersistent, dvRequestService.getDataverseRequest())); + } + } catch (Exception ex) { + logger.warning("Failed to permanently toggle the superuser status for user " + selectedUserDetached.getIdentifier() + ": " + ex.getMessage()); + } + } else { logger.warning("selectedUserPersistent is null. AuthenticatedUser not found for id: " + selectedUserDetached.getId()); } - + } public void cancelSuperuserStatusChange(){ diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java new file mode 100644 index 00000000000..dc2f0439f3f --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/GrantSuperuserStatusCommand.java @@ -0,0 +1,51 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.IdServiceBean; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.engine.command.AbstractVoidCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; + +/** + * + * @author Leonid Andreev + */ +// the permission annotation is open, since this is a superuser-only command - +// and that's enforced in the command body: +@RequiredPermissions({}) +public class GrantSuperuserStatusCommand extends AbstractVoidCommand { + + private final AuthenticatedUser targetUser; + + public GrantSuperuserStatusCommand (AuthenticatedUser targetUser, DataverseRequest aRequest) { + super(aRequest, (Dataset)null); + this.targetUser = targetUser; + } + + @Override + protected void executeImpl(CommandContext ctxt) throws CommandException { + + if (!(getUser() instanceof AuthenticatedUser) || !getUser().isSuperuser()) { + throw new PermissionException("Revoke Superuser status command can only be called by superusers.", + this, null, null); + } + + try { + targetUser.setSuperuser(true); + ctxt.em().merge(targetUser); + ctxt.em().flush(); + } catch (Exception e) { + throw new CommandException("Failed to grant the superuser status to user "+targetUser.getIdentifier(), this); + } + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java new file mode 100644 index 00000000000..47c5e3c0562 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RevokeSuperuserStatusCommand.java @@ -0,0 +1,52 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.engine.command.impl; + +import edu.harvard.iq.dataverse.Dataset; +import edu.harvard.iq.dataverse.IdServiceBean; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.engine.command.AbstractVoidCommand; +import edu.harvard.iq.dataverse.engine.command.CommandContext; +import edu.harvard.iq.dataverse.engine.command.DataverseRequest; +import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; +import edu.harvard.iq.dataverse.engine.command.exception.CommandException; +import edu.harvard.iq.dataverse.engine.command.exception.PermissionException; + +/** + * + * @author Leonid Andreev + */ +// the permission annotation is open, since this is a superuser-only command - +// and that's enforced in the command body: +@RequiredPermissions({}) +public class RevokeSuperuserStatusCommand extends AbstractVoidCommand { + + private final AuthenticatedUser targetUser; + + public RevokeSuperuserStatusCommand (AuthenticatedUser targetUser, DataverseRequest aRequest) { + super(aRequest, (Dataset)null); + this.targetUser = targetUser; + } + + @Override + protected void executeImpl(CommandContext ctxt) throws CommandException { + + if (!(getUser() instanceof AuthenticatedUser) || !getUser().isSuperuser()) { + throw new PermissionException("Revoke Superuser status command can only be called by superusers.", + this, null, null); + } + + try { + targetUser.setSuperuser(false); + ctxt.em().merge(targetUser); + ctxt.em().flush(); + } catch (Exception e) { + throw new CommandException("Failed to revoke the superuser status for user "+targetUser.getIdentifier(), this); + } + } + +} From 4abb4e96ea3314c81a04ab6df14d8adfe4eb9cfa Mon Sep 17 00:00:00 2001 From: Leonid Andreev Date: Wed, 28 Jun 2017 20:46:37 -0400 Subject: [PATCH 84/91] Per Gustavo's code review request, added commands for granting and revoking the superuser status. The commands are used by the dashboard user list page. But not the admin API. Please ask Gustavo if you have any questions about this change. Hopefully this is the last commit for #3614-#3612. --- .../iq/dataverse/dashboard/DashboardUsersPage.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 429ccff810a..5166e32986e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -36,7 +36,7 @@ public class DashboardUsersPage implements java.io.Serializable { PermissionsWrapper permissionsWrapper; @EJB EjbDataverseEngine commandEngine; - @EJB + @Inject DataverseRequestServiceBean dvRequestService; private static final Logger logger = Logger.getLogger(DashboardUsersPage.class.getCanonicalName()); @@ -184,14 +184,14 @@ public void setUserToToggleSuperuserStatus(AuthenticatedUser user) { public void saveSuperuserStatus() { // Retrieve the persistent version for saving to db - logger.info("Get persisent AuthenticatedUser for id: " + selectedUserDetached.getId()); + logger.fine("Get persisent AuthenticatedUser for id: " + selectedUserDetached.getId()); selectedUserPersistent = userService.find(selectedUserDetached.getId()); if (selectedUserPersistent != null) { - logger.info("Toggling user's " + selectedUserDetached.getIdentifier() + " superuser status; (current status: " + selectedUserDetached.isSuperuser() + ")"); - logger.info("Attempting to save user " + selectedUserDetached.getIdentifier()); + logger.fine("Toggling user's " + selectedUserDetached.getIdentifier() + " superuser status; (current status: " + selectedUserDetached.isSuperuser() + ")"); + logger.fine("Attempting to save user " + selectedUserDetached.getIdentifier()); - logger.info("selectedUserPersistent info: " + selectedUserPersistent.getId() + " set to: " + selectedUserDetached.isSuperuser()); + logger.fine("selectedUserPersistent info: " + selectedUserPersistent.getId() + " set to: " + selectedUserDetached.isSuperuser()); selectedUserPersistent.setSuperuser(selectedUserDetached.isSuperuser()); // Using the new commands for granting and revoking the superuser status: From 6d73408ae7ff4bafb1a8f8c95bac2a1af3749f47 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 29 Jun 2017 12:24:46 -0400 Subject: [PATCH 85/91] #3614 bundles for friendly AuthenticationProvider names --- src/main/java/Bundle.properties | 11 ++++- .../authorization/AuthenticationProvider.java | 47 ++++++++++++++++++- .../dashboard/DashboardUsersPage.java | 6 ++- src/main/webapp/dashboard-users.xhtml | 2 +- 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 35b0eb8e271..54715d4a01e 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1657,4 +1657,13 @@ citationFrame.banner.message=If the site below does not load, the archived data citationFrame.banner.message.here=here citationFrame.banner.closeIcon=Close this message, go to dataset citationFrame.banner.countdownMessage= This message will close in -citationFrame.banner.countdownMessage.seconds=seconds \ No newline at end of file +citationFrame.banner.countdownMessage.seconds=seconds + +# Friendly AuthenticationProvider names +authenticationProvider.name.builtin=Dataverse +authenticationProvider.name.null=(provider is unknown) +authenticationProvider.name.github=GitHub +authenticationProvider.name.google=Google +authenticationProvider.name.orcid=ORCiD +authenticationProvider.name.orcid-sandbox=ORCiD Sandbox +authenticationProvider.name.shib=Shibboleth \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java index cdf38141dc3..ec989317758 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java @@ -1,6 +1,7 @@ package edu.harvard.iq.dataverse.authorization; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.util.BundleUtil; /** * Objects that can authenticate users. The authentication process yields a unique @@ -10,6 +11,13 @@ * can be queried using the {@code isXXXAllowed()} methods. If an implementation returns {@code true} * from one of these methods, it has to implement the matching methods. * + * Note: If you are adding an implementation of this interface, please add a "friendly" name to the bundles. + * Example: ShibAuthenticationProvider implements this interface. + * (a) ShibAuthenticationProvider.getID() returns "ship" + * (b) Construct bundle name using String id "shib" from (a): + * "authenticationProvider.name." + "ship" -> + * (c) Bundle.properties entry: "authenticationProvider.name.shib=Shibboleth" + * * {@code AuthenticationPrvider}s are normally registered at startup in {@link AuthenticationServiceBean#startup()}. * * @author michael @@ -17,7 +25,7 @@ public interface AuthenticationProvider { String getId(); - + AuthenticationProviderDisplayInfo getInfo(); default boolean isPasswordUpdateAllowed() { return false; }; @@ -35,12 +43,16 @@ public interface AuthenticationProvider { default String getPersistentIdUrlPrefix() { return null; }; default String getLogo() { return null; }; + + /** * Some providers (e.g organizational ones) provide verified email addresses. * @return {@code true} if we can treat email addresses coming from this provider as verified, {@code false} otherwise. */ default boolean isEmailVerified() { return false; }; + + /** * Updates the password of the user whose id is passed. * @param userIdInProvider User id in the provider. NOT the {@link AuthenticatedUser#id}, which is internal to the installation. @@ -80,4 +92,37 @@ default void updateUserInfo( String userIdInProvider, AuthenticatedUserDisplayIn default void deleteUser( String userIdInProvider ) { throw new UnsupportedOperationException(this.toString() + " does not implement account deletions"); } + + + /** + * Given the AuthenticationProvider id, return the friendly name + * of the AuthenticationProvider as defined in the bundle + * + * If no name is defined, return the id itself + * + * @param authProviderId + * @return + */ + public static String getFriendlyName(String authProviderId){ + if (authProviderId == null){ + return BundleUtil.getStringFromBundle("authenticationProvider.name.null"); + } + + String friendlyName = BundleUtil.getStringFromBundle("authenticationProvider.name." + authProviderId); + if (friendlyName == null){ + return authProviderId; + } + return friendlyName; + } + + /** + * Given the AuthenticationProvider id, + * return the friendly name using the static method + */ + default String getFriendlyName(){ + // call static method + return BundleUtil.getStringFromBundle("authentication.human_readable." + this.getId()); + } + } + diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index 9575f150c32..7ed2aa1c1b6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -4,6 +4,7 @@ import edu.harvard.iq.dataverse.PermissionsWrapper; import edu.harvard.iq.dataverse.UserServiceBean; import edu.harvard.iq.dataverse.api.Admin; +import edu.harvard.iq.dataverse.authorization.AuthenticationProvider; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.mydata.Pager; @@ -198,5 +199,8 @@ public void cancelSuperuserStatusChange(){ selectedUserPersistent = null; } - + public String getAuthProviderFriendlyName(String authProviderId){ + + return AuthenticationProvider.getFriendlyName(authProviderId); + } } diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index 0bc4b3d6def..afaf2a0b6c5 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -66,7 +66,7 @@ - + From f32940ef1655e26428cf6610453af575433c2cc6 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Thu, 29 Jun 2017 12:50:25 -0400 Subject: [PATCH 86/91] add test for AuthenticationProvider bundle names #3614 --- .../AuthenticationProviderTest.java | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/test/java/edu/harvard/iq/dataverse/authorization/AuthenticationProviderTest.java diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/AuthenticationProviderTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/AuthenticationProviderTest.java new file mode 100644 index 00000000000..7792288718f --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/AuthenticationProviderTest.java @@ -0,0 +1,96 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.authorization; + +import edu.harvard.iq.dataverse.util.BundleUtil; +import java.util.AbstractMap.SimpleEntry; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author rmp553 + */ +public class AuthenticationProviderTest { + + public AuthenticationProviderTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Create a map used to test known AuthenticationProvider ids + * + * @return + */ + private Map getBundleTestMap(){ + return Collections.unmodifiableMap(Stream.of( + new SimpleEntry<>("builtin", "authenticationProvider.name.builtin"), + new SimpleEntry<>("github", "authenticationProvider.name.github"), + new SimpleEntry<>("google", "authenticationProvider.name.google"), + new SimpleEntry<>("orcid", "authenticationProvider.name.orcid"), + new SimpleEntry<>("orcid-sandbox", "authenticationProvider.name.orcid-sandbox"), + new SimpleEntry<>("shib", "authenticationProvider.name.shib")) + .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))); + } + + /** + * Test of getFriendlyName method, of class AuthenticationProvider. + */ + @Test + public void testGetFriendlyName() { + System.out.println("getFriendlyName"); + + Map bundleTestMap = this.getBundleTestMap(); + + // ------------------------------------------ + // Test a null + // ------------------------------------------ + String expResult = BundleUtil.getStringFromBundle("authenticationProvider.name.null"); + assertEquals(expResult, AuthenticationProvider.getFriendlyName(null)); + + // ------------------------------------------ + // Test an id w/o a bundle entry--should default to id + // ------------------------------------------ + String idNotInBundle = "id-not-in-bundle-so-use-id"; + String expResult2 = AuthenticationProvider.getFriendlyName(idNotInBundle); + assertEquals(expResult2, idNotInBundle); + + // ------------------------------------------ + // Iterate through the map and test each item + // ------------------------------------------ + bundleTestMap.forEach((authProviderId, bundleName)->{ + String expectedResult = BundleUtil.getStringFromBundle(bundleName); + assertEquals(expectedResult, AuthenticationProvider.getFriendlyName(authProviderId)); + }); + + } + + + +} From 08f2c11073b5198977956b134107c6e594765527 Mon Sep 17 00:00:00 2001 From: Michael Heppler Date: Thu, 29 Jun 2017 13:20:26 -0400 Subject: [PATCH 87/91] Minor table column width adjustments on Manage Users pg. [ref #3614] --- src/main/webapp/dashboard-users.xhtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/dashboard-users.xhtml b/src/main/webapp/dashboard-users.xhtml index afaf2a0b6c5..c3b124f21c4 100644 --- a/src/main/webapp/dashboard-users.xhtml +++ b/src/main/webapp/dashboard-users.xhtml @@ -56,7 +56,7 @@ - + @@ -65,10 +65,10 @@ - + - + From 398ae12cde2cc044c102573ee5db47f4995e692f Mon Sep 17 00:00:00 2001 From: Michael Heppler Date: Thu, 29 Jun 2017 13:24:59 -0400 Subject: [PATCH 88/91] Revised popup header text on Manage Users pg. [ref #3614] --- src/main/java/Bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 54715d4a01e..27bb7933126 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -511,7 +511,7 @@ dashboard.list_users.tbl_header.affiliation=Affiliation dashboard.list_users.tbl_header.roles=Roles dashboard.list_users.tbl_header.isSuperuser=Superuser dashboard.list_users.tbl_header.authProviderFactoryAlias=Authentication -dashboard.list_users.toggleSuperuser=Enable Superuser +dashboard.list_users.toggleSuperuser=Edit Superuser Status dashboard.list_users.toggleSuperuser.confirmationText.add=Are you sure you want to enable superuser status for user {0}? dashboard.list_users.toggleSuperuser.confirmationText.remove=Are you sure you want to disable superuser status for user {0}? dashboard.list_users.toggleSuperuser.confirm=Continue From 3dc7f6299a204ac6dbff640e0390a59592cffaa2 Mon Sep 17 00:00:00 2001 From: Brian Silverstein Date: Thu, 29 Jun 2017 15:22:38 -0400 Subject: [PATCH 89/91] Dialed back logging in user page #3614 #3612 --- .../harvard/iq/dataverse/dashboard/DashboardUsersPage.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java index b766b43f183..6b6894634e4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/dashboard/DashboardUsersPage.java @@ -177,8 +177,6 @@ public AuthenticatedUser getSelectedUserDetached() { public void setUserToToggleSuperuserStatus(AuthenticatedUser user) { - logger.info("selecting user "+user.getIdentifier()); - selectedUserDetached = user; } @@ -214,9 +212,8 @@ public void saveSuperuserStatus() { } public void cancelSuperuserStatusChange(){ - logger.info("unToggling user's "+selectedUserDetached.getIdentifier()+" superuser status; (current status: "+selectedUserDetached.isSuperuser()+")"); selectedUserDetached.setSuperuser(!selectedUserDetached.isSuperuser()); - selectedUserPersistent = null; + selectedUserPersistent = null; } public String getAuthProviderFriendlyName(String authProviderId){ From efed44773bedf2ade3c79a177895ecd2514e2ac6 Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 3 Jul 2017 13:04:29 -0400 Subject: [PATCH 90/91] #3614 add API docs, additional bundle strings for API --- doc/sphinx-guides/source/api/native-api.rst | 101 +++++++++++++++++- src/main/java/Bundle.properties | 10 +- .../edu/harvard/iq/dataverse/api/Admin.java | 6 +- .../users/AuthenticatedUser.java | 41 +++++-- .../iq/dataverse/userdata/UserListResult.java | 22 +--- .../edu/harvard/iq/dataverse/api/UtilIT.java | 6 +- 6 files changed, 151 insertions(+), 35 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index adaff1ff237..e1078c42eb8 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -559,9 +559,106 @@ Creates a global role in the Dataverse installation. The data POSTed are assumed POST http://$SERVER/api/admin/roles -List all users:: +List users with the options to search and "page" through results. Only accessible to superusers. Optional parameters: + +* ``searchTerm`` A string that matches the beginning of a user identifier, first name, last name or email address. +* ``itemsPerPage`` The number of detailed results to return. The default is 25. This number has no limit. e.g. You could set it to 1000 to return 1,000 results +* ``selectedPage`` The page of results to return. The default is 1. + + GET http://$SERVER/api/admin/list-users + +Sample output. Note the ``pagination`` section. When multiple pages of results exist, the ``selectedPage`` attribute may used. + +.. code-block:: json + + { + "status":"OK", + "data":{ + "userCount":27, + "selectedPage":1, + "pagination":{ + "isNecessary":true, + "numResults":27, + "numResultsString":"27", + "docsPerPage":25, + "selectedPageNumber":1, + "pageCount":2, + "hasPreviousPageNumber":false, + "previousPageNumber":1, + "hasNextPageNumber":true, + "nextPageNumber":2, + "startCardNumber":1, + "endCardNumber":25, + "startCardNumberString":"1", + "endCardNumberString":"25", + "remainingCards":2, + "numberNextResults":2, + "pageNumberList":[ + 1, + 2 + ] + }, + "bundleStrings":{ + "userId":"ID", + "userIdentifier":"Username", + "lastName":"Last Name ", + "firstName":"First Name ", + "email":"Email", + "affiliation":"Affiliation", + "position":"Position", + "isSuperuser":"Superuser", + "authenticationProvider":"Authentication", + "roles":"Roles", + "createdTime":"Created Time", + "lastLoginTime":"Last Login Time", + "lastApiUseTime":"Last API Use Time" + }, + "users":[ + { + "id":8, + "userIdentifier":"created1", + "lastName":"created1", + "firstName":"created1", + "email":"created1@g.com", + "affiliation":"hello", + "isSuperuser":false, + "authenticationProvider":"BuiltinAuthenticationProvider", + "roles":"Curator", + "createdTime":"2017-06-28 10:36:29.444" + }, + { + "id":9, + "userIdentifier":"created8", + "lastName":"created8", + "firstName":"created8", + "email":"created8@g.com", + "isSuperuser":false, + "authenticationProvider":"BuiltinAuthenticationProvider", + "roles":"Curator", + "createdTime":"2000-01-01 00:00:00.0" + }, + { + "id":1, + "userIdentifier":"dataverseAdmin", + "lastName":"Admin", + "firstName":"Dataverse", + "email":"dataverse@mailinator2.com", + "affiliation":"Dataverse.org", + "position":"Admin", + "isSuperuser":true, + "authenticationProvider":"BuiltinAuthenticationProvider", + "roles":"Admin, Contributor", + "createdTime":"2000-01-01 00:00:00.0", + "lastLoginTime":"2017-07-03 12:22:35.926", + "lastApiUseTime":"2017-07-03 12:55:57.186" + }, + **... 22 more user documents ...** + ] + } + } + +.. note:: "List all users" ``GET http://$SERVER/api/admin/authenticatedUsers`` is deprecated, but supported. - GET http://$SERVER/api/admin/authenticatedUsers List user whose ``identifier`` (without the ``@`` sign) is passed:: diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 27bb7933126..9f8b7a1df6d 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -504,13 +504,19 @@ dashboard.list_users.searchTerm.watermark=Search these users... dashboard.list_users.tbl_header.userId=ID dashboard.list_users.tbl_header.userIdentifier=Username dashboard.list_users.tbl_header.name=Name -dashboard.list_users.tbl_header.lastName=lastName -dashboard.list_users.tbl_header.firstName=firstName +dashboard.list_users.tbl_header.lastName=Last Name +dashboard.list_users.tbl_header.firstName=First Name dashboard.list_users.tbl_header.email=Email dashboard.list_users.tbl_header.affiliation=Affiliation dashboard.list_users.tbl_header.roles=Roles +dashboard.list_users.tbl_header.position=Position dashboard.list_users.tbl_header.isSuperuser=Superuser dashboard.list_users.tbl_header.authProviderFactoryAlias=Authentication +dashboard.list_users.tbl_header.createdTime=Created Time +dashboard.list_users.tbl_header.lastLoginTime=Last Login Time +dashboard.list_users.tbl_header.lastApiUseTime=Last API Use Time + + dashboard.list_users.toggleSuperuser=Edit Superuser Status dashboard.list_users.toggleSuperuser.confirmationText.add=Are you sure you want to enable superuser status for user {0}? dashboard.list_users.toggleSuperuser.confirmationText.remove=Are you sure you want to disable superuser status for user {0}? diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index d72221a62f8..d63f2270453 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -315,8 +315,7 @@ public Response listAuthenticatedUsers() { @Produces({"application/json"}) public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String searchTerm, @QueryParam("selectedPage") Integer selectedPage, - @QueryParam("numDisplay") Integer itemsPerPage, - @QueryParam("sortKey") String sortKey + @QueryParam("itemsPerPage") Integer itemsPerPage ) { User authUser; @@ -336,7 +335,8 @@ public Response filterAuthenticatedUsers(@QueryParam("searchTerm") String search UserListMaker userListMaker = new UserListMaker(userService); - UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, null); + String sortKey = null; + UserListResult userListResult = userListMaker.runUserSearch(searchTerm, itemsPerPage, selectedPage, sortKey); return ok(userListResult.toJSON()); } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 42444819ddf..d3427670a0e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -6,12 +6,14 @@ import edu.harvard.iq.dataverse.authorization.AuthenticatedUserLookup; import edu.harvard.iq.dataverse.userdata.UserUtil; import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.OrcidOAuth2AP; +import edu.harvard.iq.dataverse.util.BundleUtil; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import edu.harvard.iq.dataverse.util.json.NullSafeJsonBuilder; import java.io.Serializable; import java.sql.Timestamp; import java.util.List; import java.util.Objects; +import javax.json.Json; import javax.json.JsonObjectBuilder; import javax.persistence.CascadeType; import javax.persistence.Column; @@ -318,20 +320,47 @@ public JsonObjectBuilder toJson() { authenicatedUserJson.add("firstName", this.firstName); authenicatedUserJson.add("email", this.email); authenicatedUserJson.add("affiliation", UserUtil.getStringOrNull(this.affiliation)); - authenicatedUserJson.add("isSuperuser", this.superuser); authenicatedUserJson.add("position", UserUtil.getStringOrNull(this.position)); + authenicatedUserJson.add("isSuperuser", this.superuser); + + authenicatedUserJson.add("authenticationProvider", this.authProviderFactoryAlias); + authenicatedUserJson.add("roles", UserUtil.getStringOrNull(this.roles)); authenicatedUserJson.add("createdTime", UserUtil.getTimestampStringOrNull(this.createdTime)); authenicatedUserJson.add("lastLoginTime", UserUtil.getTimestampStringOrNull(this.lastLoginTime)); authenicatedUserJson.add("lastApiUseTime", UserUtil.getTimestampStringOrNull(this.lastApiUseTime)); - - authenicatedUserJson.add("authenticationProvider", this.authProviderFactoryAlias); - authenicatedUserJson.add("roles", UserUtil.getStringOrNull(this.roles)); - + return authenicatedUserJson; } - + /** + * May be used for translating API field names. + * + * Should match order of "toJson()" method + * + * @return + */ + public static JsonObjectBuilder getBundleStrings(){ + + return Json.createObjectBuilder() + .add("userId", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userId")) + .add("userIdentifier", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userIdentifier")) + .add("lastName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastName")) + .add("firstName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.firstName")) + .add("email", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.email")) + .add("affiliation", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.affiliation")) + .add("position", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.position")) + .add("isSuperuser", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.isSuperuser")) + + .add("authenticationProvider", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.authProviderFactoryAlias")) + .add("roles", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.roles")) + + .add("createdTime", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.createdTime")) + .add("lastLoginTime", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastLoginTime")) + .add("lastApiUseTime", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastApiUseTime")) + ; + + } @Override public String toString() { diff --git a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java index 99438e6fa06..07937638607 100644 --- a/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java +++ b/src/main/java/edu/harvard/iq/dataverse/userdata/UserListResult.java @@ -169,7 +169,7 @@ public JsonObjectBuilder toJSON(){ jsonOverallData.add("userCount", pager.getNumResults()) .add("selectedPage", pager.getSelectedPageNumber()) .add("pagination", pager.asJsonObjectBuilder()) - .add("bundleStrings", getBundleStrings()) + .add("bundleStrings", AuthenticatedUser.getBundleStrings()) .add("users", getUsersAsJSONArray()) ; return jsonOverallData; @@ -203,26 +203,10 @@ private JsonObjectBuilder getNoResultsJSON(){ return Json.createObjectBuilder() .add("userCount", 0) .add("selectedPage", 1) - .add("bundleStrings", getBundleStrings()) + .add("bundleStrings", AuthenticatedUser.getBundleStrings()) .add("users", Json.createArrayBuilder()); // empty array } - /** - * May be used for table headers or translating field names - * - * @return - */ - public JsonObjectBuilder getBundleStrings(){ - - return Json.createObjectBuilder() - .add("userId", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userId")) - .add("userIdentifier", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.userIdentifier")) - .add("lastName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.lastName")) - .add("firstName", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.firstName")) - .add("email", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.email")) - .add("isSuperuser", BundleUtil.getStringFromBundle("dashboard.list_users.tbl_header.isSuperuser")) - ; - - } + } 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 0b7dfd62b21..59d1e0f6270 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -654,7 +654,7 @@ static Response getAuthenticatedUser(String userIdentifier, String apiToken) { static Response filterAuthenticatedUsers(String superUserApiToken, String searchTerm, Integer selectedPage, - Integer numDisplay + Integer itemsPerPage // String sortKey ) { @@ -666,8 +666,8 @@ static Response filterAuthenticatedUsers(String superUserApiToken, if (selectedPage != null){ queryParams.add("selectedPage=" + selectedPage.toString()); } - if (numDisplay != null){ - queryParams.add("numDisplay=" + numDisplay.toString()); + if (itemsPerPage != null){ + queryParams.add("itemsPerPage=" + itemsPerPage.toString()); } String queryString = ""; From 6db219c8401962c80535c365fd90421452429cfb Mon Sep 17 00:00:00 2001 From: Raman Prasad Date: Mon, 3 Jul 2017 13:23:42 -0400 Subject: [PATCH 91/91] #3614, updated attribute names to not use 'card' terminology. e.g. 'startCardNumber' switched to 'startResultNumber' --- doc/sphinx-guides/source/api/native-api.rst | 16 ++++--- .../iq/dataverse/mydata/DataRetrieverAPI.java | 2 +- .../harvard/iq/dataverse/mydata/Pager.java | 44 +++++++++++++++++-- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index e1078c42eb8..846eb01683c 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -567,7 +567,11 @@ List users with the options to search and "page" through results. Only accessibl GET http://$SERVER/api/admin/list-users -Sample output. Note the ``pagination`` section. When multiple pages of results exist, the ``selectedPage`` attribute may used. + +Sample output appears below. + +* When multiple pages of results exist, the ``selectedPage`` parameters may be specified. +* Note, the resulting ``pagination`` section includes ``pageCount``, ``previousPageNumber``, ``nextPageNumber``, and other variables that may be used to re-create the UI. .. code-block:: json @@ -587,11 +591,11 @@ Sample output. Note the ``pagination`` section. When multiple pages of results "previousPageNumber":1, "hasNextPageNumber":true, "nextPageNumber":2, - "startCardNumber":1, - "endCardNumber":25, - "startCardNumberString":"1", - "endCardNumberString":"25", - "remainingCards":2, + "startResultNumber":1, + "endResultNumber":25, + "startResultNumberString":"1", + "endResultNumberString":"25", + "remainingResults":2, "numberNextResults":2, "pageNumberList":[ 1, diff --git a/src/main/java/edu/harvard/iq/dataverse/mydata/DataRetrieverAPI.java b/src/main/java/edu/harvard/iq/dataverse/mydata/DataRetrieverAPI.java index b9efe945333..c369c1f52e0 100644 --- a/src/main/java/edu/harvard/iq/dataverse/mydata/DataRetrieverAPI.java +++ b/src/main/java/edu/harvard/iq/dataverse/mydata/DataRetrieverAPI.java @@ -452,7 +452,7 @@ public String retrieveMyDataAsJsonString(@QueryParam("dvobject_types") List