/* * Copyright 2015-2016 OpenCB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.opencb.opencga.server.rest; import io.swagger.annotations.*; import org.apache.commons.lang3.StringUtils; import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.commons.datastore.core.QueryResult; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.models.File; import org.opencb.opencga.catalog.models.Project; import org.opencb.opencga.catalog.models.Session; import org.opencb.opencga.catalog.models.User; import org.opencb.opencga.core.exception.VersionException; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; @Path("/{version}/users") @Produces(MediaType.APPLICATION_JSON) @Api(value = "Users", position = 1, description = "Methods for working with 'users' endpoint") public class UserWSServer extends OpenCGAWSServer { public UserWSServer(@Context UriInfo uriInfo, @Context HttpServletRequest httpServletRequest) throws IOException, VersionException { super(uriInfo, httpServletRequest); } @GET @Path("/create") @ApiOperation(value = "Create a new user [WARNING]", response = User.class, notes = "WARNING: the usage of this web service is discouraged, please use the POST version instead. Be aware that this is web service " + "is not tested and this can be deprecated in a future version.") public Response createUser(@ApiParam(value = "User id", required = true) @QueryParam("userId") String userId, @ApiParam(value = "User name", required = true) @QueryParam("name") String name, @ApiParam(value = "User's email", required = true) @QueryParam("email") String email, @ApiParam(value = "User's password", required = true) @QueryParam("password") String password, @ApiParam(value = "User's organization") @QueryParam("organization") String organization) { try { queryOptions.remove("password"); QueryResult queryResult = catalogManager.createUser(userId, name, email, password, organization, null, queryOptions); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/create") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Create a new user", response = User.class) public Response createUserPost(@ApiParam(value = "JSON containing the parameters 'userId', 'name', 'email' and 'password' " + "and, optionally, 'organization'", required = true) Map<String, String> map) { try { if (!map.containsKey("userId") || !map.containsKey("name") || !map.containsKey("email") || !map.containsKey("password")) { createErrorResponse(new CatalogException("userId, name, email or password not present")); } String userId = map.get("userId"); String name = map.get("name"); String email = map.get("email"); String password = map.get("password"); String organization = map.containsKey("organization") ? map.get("organization") : ""; QueryResult queryResult = catalogManager.createUser(userId, name, email, password, organization, null, queryOptions); return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/info") @ApiOperation(value = "Return the user information including its projects and studies", response = User.class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Set which fields are included in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Set which fields are excluded in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), }) public Response getInfo(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "This parameter shows the last time the user information was modified. When " + "the value passed corresponds with the user's last activity registered, an empty result will be " + "returned meaning that the client already has the most up to date user information.", hidden = true) @QueryParam ("lastModified") String lastModified) { try { QueryResult result = catalogManager.getUser(userId, lastModified, queryOptions, sessionId); return createOkResponse(result); } catch (Exception e) { return createErrorResponse(e); } } @Deprecated @GET @Path("/{user}/login") @ApiOperation(value = "Get identified and gain access to the system [DEPRECATED]" , hidden = true) public Response login(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "User password", required = true) @QueryParam("password") String password) { sessionIp = httpServletRequest.getRemoteAddr(); QueryResult<Session> queryResult; try { queryOptions.remove("password"); //Remove password from query options queryResult = catalogManager.login(userId, password, sessionIp); ObjectMap sessionMap = new ObjectMap(); sessionMap.append("sessionId", queryResult.first().getId()) .append("id", queryResult.first().getId()) .append("ip", queryResult.first().getIp()) .append("date", queryResult.first().getDate()); QueryResult<ObjectMap> login = new QueryResult<>("You successfully logged in", queryResult.getDbTime(), 1, 1, queryResult.getWarningMsg(), queryResult.getErrorMsg(), Arrays.asList(sessionMap)); return createOkResponse(login); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{user}/login") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Get identified and gain access to the systemn") public Response loginPost(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "JSON containing the parameter 'password'", required = true) Map<String, String> map) { sessionIp = httpServletRequest.getRemoteAddr(); QueryResult<Session> queryResult; try { if (!map.containsKey("password")) { throw new Exception("The json does not contain the key password."); } String password = map.get("password"); queryResult = catalogManager.login(userId, password, sessionIp); ObjectMap sessionMap = new ObjectMap(); sessionMap.append("sessionId", queryResult.first().getId()) .append("id", queryResult.first().getId()) .append("ip", queryResult.first().getIp()) .append("date", queryResult.first().getDate()); QueryResult<ObjectMap> login = new QueryResult<>("You successfully logged in", queryResult.getDbTime(), 1, 1, queryResult .getWarningMsg(), queryResult.getErrorMsg(), Arrays.asList(sessionMap)); return createOkResponse(login); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/logout") @ApiOperation(value = "End user session") public Response logout(@ApiParam(value = "userId", required = true) @PathParam("user") String userId) { try { QueryResult result = catalogManager.logout(userId, sessionId); result.setId("You successfully logged out"); return createOkResponse(result); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{user}/change-password") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Change the password of a user") public Response changePasswordPost(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "JSON containing the params 'password' (old password) and 'npassword' (new " + "password)", required = true) ObjectMap params) { try { if (!params.containsKey("password") || !params.containsKey("npassword")) { throw new Exception("The json must contain the keys password and npassword."); } String password = params.getString("password"); String nPassword = params.getString("npassword"); QueryResult result = catalogManager.changePassword(userId, password, nPassword); return createOkResponse(result); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/reset-password") @ApiOperation(value = "Reset password", notes = "Reset the user's password and send a new random one to the e-mail stored in catalog.") public Response resetPassword(@ApiParam(value = "User id", required = true) @PathParam("user") String userId) { try { QueryResult result = catalogManager.getUserManager().resetPassword(userId, sessionId); return createOkResponse(result); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/projects") @ApiOperation(value = "Retrieve the projects of the user", notes = "Retrieve the list of projects and studies belonging or shared with " + "the user", response = Project[].class) @ApiImplicitParams({ @ApiImplicitParam(name = "include", value = "Set which fields are included in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "exclude", value = "Set which fields are excluded in the response, e.g.: name,alias...", dataType = "string", paramType = "query"), @ApiImplicitParam(name = "limit", value = "Max number of results to be returned.", dataType = "integer", paramType = "query"), @ApiImplicitParam(name = "skip", value = "Number of results to be skipped.", dataType = "integer", paramType = "query") }) public Response getAllProjects(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "When false, it will return only the projects and studies belonging to the user. " + "However, if this parameter is set to true, it will also show the projects and studies " + "shared with the user.", defaultValue = "false") @QueryParam ("shared") boolean shared) { try { QueryResult<Project> queryResult = catalogManager.getAllProjects(userId, queryOptions, sessionId); if (shared) { QueryResult<Project> sharedResults = catalogManager.getProjectManager().getSharedProjects(userId, queryOptions, sessionId); queryResult.getResult().addAll(sharedResults.getResult()); queryResult.setNumTotalResults(queryResult.getNumTotalResults() + sharedResults.getNumTotalResults()); queryResult.setNumResults(queryResult.getNumResults() + sharedResults.getNumResults()); queryResult.setDbTime(queryResult.getDbTime() + sharedResults.getDbTime()); } return createOkResponse(queryResult); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/update") @ApiOperation(value = "Update some user attributes [WARNING]", response = User.class, notes = "WARNING: the usage of this web service is discouraged, please use the POST version instead. Be aware that this is web service " + "is not tested and this can be deprecated in a future version.") public Response update(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "User name") @QueryParam("name") String name, @ApiParam(value = "User's email") @QueryParam("email") String email, @ApiParam(value = "User's organization") @QueryParam("organization") String organization, @ApiParam(value = "JSON string containing additional information to be stored") @QueryParam("attributes") String attributes) { try { ObjectMap objectMap = new ObjectMap(); objectMap.putIfNotNull("name", name); objectMap.putIfNotNull("email", email); objectMap.putIfNotNull("organization", organization); objectMap.putIfNotNull("attributes", attributes); QueryResult result = catalogManager.modifyUser(userId, objectMap, sessionId); return createOkResponse(result); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{user}/update") @Consumes(MediaType.APPLICATION_JSON) @ApiOperation(value = "Update some user attributes", position = 9, response = User.class) public Response updateByPost(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(name = "params", value = "JSON containing the params to be updated. Supported keys " + "are: 'name', 'email', 'organization' and 'attributes'", required = true) ObjectMap params) { try { QueryResult result = catalogManager.modifyUser(userId, params, sessionId); return createOkResponse(result); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/delete") @ApiOperation(value = "Delete a user [NOT TESTED]") public Response delete(@ApiParam(value = "Comma separated list of user ids", required = true) @PathParam("user") String userId) { try { List<QueryResult<User>> deletedUsers = catalogManager.getUserManager().delete(userId, queryOptions, sessionId); return createOkResponse(deletedUsers); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/configs/create") @ApiOperation(value = "Store a user configuration", notes = "Some applications might want to store some configuration parameters " + "containing the preferences of the user. The intention of this is to provide a place to store this things for every user.", response = Map.class, hidden = true) public Response setConfiguration(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Unique name (typically the name of the application)", required = true) @QueryParam("name") String name, @ApiParam(name = "params", value = "JSON string containing anything useful for the application " + "such as user or default preferences", required = true) String parameters) { try { return createOkResponse(catalogManager.getUserManager().setConfig(userId, sessionId, name, new ObjectMap(parameters))); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{user}/configs/create") @ApiOperation(value = "Store a user configuration", notes = "Some applications might want to store some configuration parameters " + "containing the preferences of the user. The aim of this is to provide a place to store this things for every user.", response = Map.class) public Response setConfigurationPOST(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Unique name (typically the name of the application)", required = true) @QueryParam("name") String name, @ApiParam(name = "params", value = "JSON containing anything useful for the application such as user or default " + "preferences", required = true) ObjectMap params) { try { return createOkResponse(catalogManager.getUserManager().setConfig(userId, sessionId, name, params)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/configs/{name}/delete") @ApiOperation(value = "Delete a user configuration", response = Map.class) public Response deleteConfiguration(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Unique name (typically the name of the application)", required = true) @PathParam("name") String name) { try { return createOkResponse(catalogManager.getUserManager().deleteConfig(userId, sessionId, name)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/configs/{name}/info") @ApiOperation(value = "Fetch a user configuration", response = Map.class) public Response getConfiguration(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Unique name (typically the name of the application)", required = true) @PathParam("name") String name) { try { return createOkResponse(catalogManager.getUserManager().getConfig(userId, sessionId, name)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/configs/filters/create") @ApiOperation(value = "Store a custom filter", notes = "Users normally try to query the data using the same filters most of " + "the times. The aim of this WS is to allow storing as many different filters as the user might want in order not to type " + "the same filters.", response = User.Filter.class, hidden = true) public Response addFilter(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Name of the filter", required = true) @QueryParam("name") String name, @ApiParam(value = "Bioformat for which the filters will make sense (generally VARIANT or ALIGNMENT). The " + "whole list of allowed bioformats can be checked in the files webservice /files/bioformats") @QueryParam("bioformat") String bioformatStr, @ApiParam(value = "Description of the filter") @QueryParam("description") String description, @ApiParam(value = "JSON string containing the query to be stored") @QueryParam("query") String queryStr, @ApiParam(value = "JSON string containing modifiers of the result") @QueryParam("queryOptions") String queryOptionsStr) { File.Bioformat bioformat = File.Bioformat.UNKNOWN; if (StringUtils.isNotEmpty(bioformatStr)) { try { bioformat = File.Bioformat.valueOf(bioformatStr.toUpperCase()); } catch (Exception e) { return createErrorResponse(new CatalogException("Bioformat " + bioformatStr + " is not a valid bioformat.")); } } try { Query myQuery; QueryOptions myOptions; if (StringUtils.isNotEmpty(queryStr)) { myQuery = new Query(queryStr); } else { myQuery = new Query(); } if (StringUtils.isNotEmpty(queryOptionsStr)) { myOptions = new QueryOptions(queryOptionsStr); } else { myOptions = new QueryOptions(); } return createOkResponse(catalogManager.getUserManager().addFilter(userId, sessionId, name, description, bioformat, myQuery, myOptions)); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{user}/configs/filters/create") @ApiOperation(value = "Store a custom filter", notes = "Users normally try to query the data using the same filters most of " + "the times. The aim of this WS is to allow storing as many different filters as the user might want in order not to type " + "the same filters.", response = User.Filter.class) public Response addFilterPOST(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(name = "params", value = "Filter parameters", required = true) User.Filter params) { try { return createOkResponse(catalogManager.getUserManager().addFilter(userId, sessionId, params.getName(), params.getDescription(), params.getBioformat(), params.getQuery(), params.getOptions())); } catch (Exception e) { return createErrorResponse(e); } } private static class UpdateFilter { public File.Bioformat bioformat; public String description; public Query query; public QueryOptions options; } @GET @Path("/{user}/configs/filters/{name}/update") @ApiOperation(value = "Update a custom filter", response = User.Filter.class, hidden = true) public Response updateFilter(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Filter name", required = true) @PathParam("name") String name, @ApiParam(value = "Bioformat for which the filters will make sense (generally VARIANT or ALIGNMENT). The " + "whole list of allowed bioformats can be checked in the files webservice /files/bioformats") @QueryParam("bioformat") String bioformatStr, @ApiParam(value = "Description of the filter") @QueryParam("description") String description, @ApiParam(value = "JSON string containing the query to be stored") @QueryParam("query") String queryStr, @ApiParam(value = "JSON string containing modifiers of the result") @QueryParam("queryOptions") String queryOptionsStr) { try { ObjectMap params = new ObjectMap(); params.putIfNotEmpty("bioformat", bioformatStr); params.putIfNotEmpty("description", description); if (StringUtils.isNotEmpty(queryStr)) { params.put("query", new Query(queryStr)); } if (StringUtils.isNotEmpty(queryOptionsStr)) { params.put("options", new QueryOptions(queryOptionsStr)); } return createOkResponse(catalogManager.getUserManager().updateFilter(userId, sessionId, name, params)); } catch (Exception e) { return createErrorResponse(e); } } @POST @Path("/{user}/configs/filters/{name}/update") @ApiOperation(value = "Update a custom filter", response = User.Filter.class) public Response updateFilterPOST(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Filter name", required = true) @PathParam("name") String name, @ApiParam(name = "params", value = "Filter parameters", required = true) UpdateFilter params) { try { return createOkResponse(catalogManager.getUserManager().updateFilter(userId, sessionId, name, new ObjectMap(jsonObjectMapper.writeValueAsString(params)))); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/configs/filters/{name}/delete") @ApiOperation(value = "Delete a custom filter", response = User.Filter.class) public Response deleteFilter(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Filter name", required = true) @PathParam("name") String name) { try { return createOkResponse(catalogManager.getUserManager().deleteFilter(userId, sessionId, name)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/configs/filters/{name}/info") @ApiOperation(value = "Fetch a filter", response = User.Filter.class) public Response getFilter(@ApiParam(value = "User id", required = true) @PathParam("user") String userId, @ApiParam(value = "Filter name", required = true) @PathParam("name") String name) { try { return createOkResponse(catalogManager.getUserManager().getFilter(userId, sessionId, name)); } catch (Exception e) { return createErrorResponse(e); } } @GET @Path("/{user}/configs/filters/list") @ApiOperation(value = "Fetch all the filters of a user", response = User.Filter.class) public Response getFilters(@ApiParam(value = "User id", required = true) @PathParam("user") String userId) { try { return createOkResponse(catalogManager.getUserManager().getAllFilters(userId, sessionId)); } catch (Exception e) { return createErrorResponse(e); } } }