/*
* 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.catalog.db.mongodb;
import com.mongodb.DuplicateKeyException;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.apache.commons.lang3.NotImplementedException;
import org.bson.Document;
import org.bson.conversions.Bson;
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.commons.datastore.mongodb.MongoDBCollection;
import org.opencb.opencga.catalog.db.api.DBIterator;
import org.opencb.opencga.catalog.db.api.ProjectDBAdaptor;
import org.opencb.opencga.catalog.db.api.UserDBAdaptor;
import org.opencb.opencga.catalog.db.mongodb.converters.UserConverter;
import org.opencb.opencga.catalog.exceptions.CatalogDBException;
import org.opencb.opencga.catalog.exceptions.CatalogException;
import org.opencb.opencga.catalog.models.Project;
import org.opencb.opencga.catalog.models.Session;
import org.opencb.opencga.catalog.models.Status;
import org.opencb.opencga.catalog.models.User;
import org.opencb.opencga.core.common.TimeUtils;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.function.Consumer;
import static org.opencb.opencga.catalog.db.api.UserDBAdaptor.QueryParams.*;
import static org.opencb.opencga.catalog.db.mongodb.MongoDBUtils.*;
/**
* @author Jacobo Coll <jacobo167@gmail.com>
*/
public class UserMongoDBAdaptor extends MongoDBAdaptor implements UserDBAdaptor {
private final MongoDBCollection userCollection;
private UserConverter userConverter;
public UserMongoDBAdaptor(MongoDBCollection userCollection, MongoDBAdaptorFactory dbAdaptorFactory) {
super(LoggerFactory.getLogger(UserMongoDBAdaptor.class));
this.dbAdaptorFactory = dbAdaptorFactory;
this.userCollection = userCollection;
this.userConverter = new UserConverter();
}
/*
* *************************
* User methods
* ***************************
*/
@Override
public QueryResult<User> insert(User user, QueryOptions options) throws CatalogDBException {
checkParameter(user, "user");
long startTime = startQuery();
if (exists(user.getId())) {
throw new CatalogDBException("User {id:\"" + user.getId() + "\"} already exists");
}
List<Project> projects = user.getProjects();
user.setProjects(Collections.<Project>emptyList());
user.setLastModified(TimeUtils.getTimeMillis());
Document userDocument = userConverter.convertToStorageType(user);
userDocument.append(PRIVATE_ID, user.getId());
QueryResult insert;
try {
insert = userCollection.insert(userDocument, null);
} catch (DuplicateKeyException e) {
throw new CatalogDBException("User {id:\"" + user.getId() + "\"} already exists");
}
// Although using the converters we could be inserting the user directly, we could be inserting more than users and projects if
// the projects given contains the studies, files, samples... all in the same collection. For this reason, we make different calls
// to the createProject method that is able to control these things and will create the studies, files... in their corresponding
// collections.
String errorMsg = insert.getErrorMsg() != null ? insert.getErrorMsg() : "";
for (Project p : projects) {
String projectErrorMsg = dbAdaptorFactory.getCatalogProjectDbAdaptor().insert(p, user.getId(), options).getErrorMsg();
if (projectErrorMsg != null && !projectErrorMsg.isEmpty()) {
errorMsg += ", " + p.getAlias() + ":" + projectErrorMsg;
}
}
//Get the inserted user.
user.setProjects(projects);
List<User> result = get(user.getId(), options, "null").getResult();
return endQuery("insertUser", startTime, result, errorMsg, null);
}
@Override
public QueryResult<Session> addSession(String userId, Session session) throws CatalogDBException {
long startTime = startQuery();
Bson query = new Document(QueryParams.ID.key(), userId);
Bson updates = Updates.push("sessions",
new Document("$each", Arrays.asList(getMongoDBDocument(session, "Session"))));
// .append("$slice", -50));
QueryResult<UpdateResult> update = userCollection.update(query, updates, null);
if (update.first().getModifiedCount() == 0) {
throw new CatalogDBException("An internal error occurred when logging the user" + userId);
}
// ObjectMap resultObjectMap = new ObjectMap();
// resultObjectMap.put("sessionId", session.getId());
// resultObjectMap.put("userId", userId);
return endQuery("Login", startTime, Collections.singletonList(session));
}
@Override
public QueryResult<Session> logout(String userId, String sessionId) throws CatalogDBException {
long startTime = startQuery();
String userIdBySessionId = getUserIdBySessionId(sessionId);
if (userIdBySessionId.isEmpty()) {
return endQuery("logout", startTime, null, "", "Session not found");
}
List<Session> retSession = Collections.emptyList();
if (userIdBySessionId.equals(userId)) {
// Get the session object
List<Bson> aggregates = new ArrayList<>();
aggregates.add(Aggregates.match(Filters.eq("id", userId)));
aggregates.add(Aggregates.unwind("$sessions"));
aggregates.add(Aggregates.match(Filters.eq("sessions.id", sessionId)));
QueryResult<User> aggregate = userCollection.aggregate(aggregates, userConverter, new QueryOptions());
if (aggregate.first() != null && aggregate.first().getSessions() != null && aggregate.first().getSessions().size() == 1) {
retSession = aggregate.first().getSessions();
// Remove the session object
Bson query = new Document(QueryParams.ID.key(), userId);
Bson update = new Document("$pull", new Document("sessions", new Document("id", sessionId)));
QueryResult<UpdateResult> updateQueryResult = userCollection.update(query, update, null);
if (updateQueryResult.first().getModifiedCount() == 0) {
throw new CatalogDBException("Internal error: Could not remove closed session from user " + userId);
}
} else {
throw new CatalogDBException("Internal error: Could not obtain session object from user " + userId + " when attempting to "
+ "logout");
}
// Bson query = new Document(QueryParams.SESSION_ID.key(), sessionId);
// Bson updates = Updates.set("sessions.$.logout", TimeUtils.getTime());
// userCollection.update(query, updates, null);
} else {
throw new CatalogDBException("UserId mismatches with the sessionId");
}
return endQuery("Logout", startTime, retSession);
}
@Override
public QueryResult<ObjectMap> loginAsAnonymous(Session session) throws CatalogException {
long startTime = startQuery();
QueryResult<Long> countSessions = count(new Query(QueryParams.SESSION_ID.key(), session.getId()));
if (countSessions.getResult().get(0) != 0) {
throw new CatalogDBException("Error, sessionID already exists");
}
String userId = "anonymous_" + session.getId();
User user = new User(userId, "Anonymous", "", "", "", User.UserStatus.READY);
user.getSessions().add(session);
// DBObject anonymous = getDbObject(user, "User");
Document anonymous = getMongoDBDocument(user, "User");
anonymous.put(PRIVATE_ID, user.getId());
userCollection.insert(anonymous, null);
// try {
// } catch (MongoException.DuplicateKey e) {
// throw new CatalogDBException("Anonymous user {id:\"" + user.getId() + "\"} already exists");
// }
ObjectMap resultObjectMap = new ObjectMap();
resultObjectMap.put("sessionId", session.getId());
resultObjectMap.put("userId", userId);
return endQuery("Login as anonymous", startTime, Collections.singletonList(resultObjectMap));
}
@Override
public QueryResult logoutAnonymous(String sessionId) throws CatalogDBException {
long startTime = startQuery();
String userId = "anonymous_" + sessionId;
logout(userId, sessionId);
clean(userId);
return endQuery("Logout anonymous", startTime);
}
@Override
public QueryResult<User> get(String userId, QueryOptions options, String lastModified) throws CatalogDBException {
// long startTime = startQuery();
// if (!userExists(userId)) {
// throw CatalogDBException.idNotFound("User", userId);
// }
// DBObject query = new BasicDBObject(PRIVATE_ID, userId);
// query.put("lastModified", new BasicDBObject("$ne", lastModified));
// QueryResult<DBObject> result = userCollection.find(query, options);
// User user = parseUser(result);
// if (user == null) {
// return endQuery("Get user", startTime); // user exists but no different lastModified was found: return empty result
// } else {
// joinFields(user, options);
// return endQuery("Get user", startTime, Collections.singletonList(user));
// }
checkId(userId);
Query query = new Query(QueryParams.ID.key(), userId).append(QueryParams.STATUS_NAME.key(), "!=" + Status.DELETED);
if (lastModified != null && !lastModified.isEmpty()) {
query.append(QueryParams.LAST_MODIFIED.key(), "!=" + lastModified);
}
return get(query, options);
}
@Override
public QueryResult changePassword(String userId, String oldPassword, String newPassword) throws CatalogDBException {
long startTime = startQuery();
// BasicDBObject query = new BasicDBObject("id", userId);
// query.put("password", oldPassword);
Query query = new Query(QueryParams.ID.key(), userId);
query.append(QueryParams.PASSWORD.key(), oldPassword);
Bson bson = parseQuery(query);
// BasicDBObject fields = new BasicDBObject("password", newPassword);
// BasicDBObject action = new BasicDBObject("$set", fields);
// Bson set = Updates.set("password", new Document("password", newPassword));
Bson set = Updates.set("password", newPassword);
// QueryResult<WriteResult> update = userCollection.update(bson, set, null);
QueryResult<UpdateResult> update = userCollection.update(bson, set, null);
if (update.getResult().get(0).getModifiedCount() == 0) { //0 query matches.
throw new CatalogDBException("Bad user or password");
}
return endQuery("Change Password", startTime, update);
}
@Override
public void updateUserLastModified(String userId) throws CatalogDBException {
update(userId, new ObjectMap("lastModified", TimeUtils.getTimeMillis()));
}
@Override
public QueryResult resetPassword(String userId, String email, String newCryptPass) throws CatalogDBException {
long startTime = startQuery();
// BasicDBObject query = new BasicDBObject("id", userId);
// query.put("email", email);
Query query = new Query(QueryParams.ID.key(), userId);
query.append(QueryParams.EMAIL.key(), email);
Bson bson = parseQuery(query);
// BasicDBObject fields = new BasicDBObject("password", newCryptPass);
// BasicDBObject action = new BasicDBObject("$set", fields);
Bson set = Updates.set("password", new Document("password", newCryptPass));
// QueryResult<WriteResult> update = userCollection.update(query, action, null);
QueryResult<UpdateResult> update = userCollection.update(bson, set, null);
if (update.getResult().get(0).getModifiedCount() == 0) { //0 query matches.
throw new CatalogDBException("Bad user or email");
}
return endQuery("Reset Password", startTime, Arrays.asList("Password successfully changed"));
}
@Override
public QueryResult<Session> getSession(String userId, String sessionId) throws CatalogDBException {
long startTime = startQuery();
// BasicDBObject query = new BasicDBObject("id", userId);
// query.put("sessions.id", sessionId);
Query query1 = new Query(QueryParams.ID.key(), userId)
.append(QueryParams.SESSION_ID.key(), sessionId);
Bson bson = parseQuery(query1);
// BasicDBObject projection = new BasicDBObject("sessions",
// new BasicDBObject("$elemMatch",
// new BasicDBObject("id", sessionId)));
Bson projection = Projections.elemMatch("sessions", Filters.eq("id", sessionId));
// QueryResult<DBObject> result = userCollection.find(query, projection, null);
QueryResult<Document> documentQueryResult = userCollection.find(bson, projection, null);
User user = parseUser(documentQueryResult);
if (user != null) {
return endQuery("getSession", startTime, user.getSessions());
}
return endQuery("getSession", startTime, Arrays.asList());
}
@Override
public String getUserIdBySessionId(String sessionId) {
Bson query = new Document("sessions", new Document("$elemMatch", new Document("id", sessionId)));
Bson projection = Projections.include(QueryParams.ID.key());
QueryResult<Document> id = userCollection.find(query, projection, null);
if (id.getNumResults() != 0) {
return (String) (id.getResult().get(0)).get("id");
} else {
return "";
}
}
@Override
public QueryResult setConfig(String userId, String name, ObjectMap config) throws CatalogDBException {
long startTime = startQuery();
// Set the config
Bson bsonQuery = Filters.eq(QueryParams.ID.key(), userId);
Bson filterDocument = getMongoDBDocument(config, "Config");
Bson update = Updates.set(QueryParams.CONFIGS.key() + "." + name, filterDocument);
QueryResult<UpdateResult> queryResult = userCollection.update(bsonQuery, update, null);
if (queryResult.first().getModifiedCount() == 0) {
throw new CatalogDBException("Could not create " + name + " configuration ");
}
QueryResult<User> userQueryResult = get(userId, new QueryOptions(), "");
if (userQueryResult.getNumResults() == 0) {
throw new CatalogDBException("Internal error: Could not retrieve user " + userId + " information");
}
return endQuery("Set config", startTime, Arrays.asList(userQueryResult.first().getConfigs().get(name)));
}
@Override
public QueryResult<Long> deleteConfig(String userId, String name) throws CatalogDBException {
long startTime = startQuery();
// Insert the config
Bson bsonQuery = Filters.and(
Filters.eq(QueryParams.ID.key(), userId),
Filters.exists(QueryParams.CONFIGS.key() + "." + name)
);
Bson update = Updates.unset(QueryParams.CONFIGS.key() + "." + name);
QueryResult<UpdateResult> queryResult = userCollection.update(bsonQuery, update, null);
if (queryResult.first().getModifiedCount() == 0) {
throw new CatalogDBException("Could not delete " + name + " configuration ");
}
QueryResult<User> userQueryResult = get(userId, new QueryOptions(), "");
if (userQueryResult.getNumResults() == 0) {
throw new CatalogDBException("Internal error: Could not retrieve user " + userId + " information");
}
return endQuery("Delete config", startTime, Arrays.asList(queryResult.first().getModifiedCount()));
}
@Override
public QueryResult<User.Filter> addFilter(String userId, User.Filter filter) throws CatalogDBException {
long startTime = startQuery();
// Insert the filter
Bson bsonQuery = Filters.and(
Filters.eq(QueryParams.ID.key(), userId),
Filters.ne(QueryParams.CONFIGS_FILTERS_NAME.key(), filter.getName())
);
Bson filterDocument = getMongoDBDocument(filter, "Filter");
Bson update = Updates.push(QueryParams.CONFIGS_FILTERS.key(), filterDocument);
QueryResult<UpdateResult> queryResult = userCollection.update(bsonQuery, update, null);
if (queryResult.first().getModifiedCount() != 1) {
if (queryResult.first().getModifiedCount() == 0) {
throw new CatalogDBException("Internal error: The filter could not be stored.");
} else {
// This error should NEVER be raised.
throw new CatalogDBException("User: There was a critical error when storing the filter. Is has been inserted "
+ queryResult.first().getModifiedCount() + " times.");
}
}
return endQuery("addFilter", startTime, Arrays.asList(filter));
}
@Override
public QueryResult<Long> updateFilter(String userId, String name, ObjectMap params) throws CatalogDBException {
long startTime = startQuery();
if (params.isEmpty()) {
throw new CatalogDBException("Nothing to be updated. No parameters were passed.");
}
final String prefixUpdate = CONFIGS_FILTERS.key() + ".$.";
Document parameters = new Document();
if (params.get(FilterParams.DESCRIPTION.key()) != null) {
parameters.put(prefixUpdate + FilterParams.DESCRIPTION.key(), params.get(FilterParams.DESCRIPTION.key()));
}
if (params.get(FilterParams.BIOFORMAT.key()) != null) {
parameters.put(prefixUpdate + FilterParams.BIOFORMAT.key(), params.get(FilterParams.BIOFORMAT.key()).toString());
}
if (params.get(FilterParams.QUERY.key()) != null) {
parameters.put(prefixUpdate + FilterParams.QUERY.key(), getMongoDBDocument(params.get(FilterParams.QUERY.key()), "Query"));
}
if (params.get(FilterParams.OPTIONS.key()) != null) {
parameters.put(prefixUpdate + FilterParams.OPTIONS.key(), getMongoDBDocument(params.get(FilterParams.OPTIONS.key()),
"Options"));
}
if (parameters.isEmpty()) {
throw new CatalogDBException("Nothing to be updated. Parameters were not recognised.");
}
Query query = new Query()
.append(ID.key(), userId)
.append(CONFIGS_FILTERS_NAME.key(), name);
QueryResult<UpdateResult> update = userCollection.update(parseQuery(query), new Document("$set", parameters), null);
return endQuery("Update filter", startTime, Arrays.asList(update.first().getModifiedCount()));
}
@Override
public QueryResult deleteFilter(String userId, String name) throws CatalogDBException {
long startTime = startQuery();
// Delete the filter
Bson bsonQuery = Filters.and(
Filters.eq(QueryParams.ID.key(), userId),
Filters.eq(QueryParams.CONFIGS_FILTERS_NAME.key(), name)
);
Bson update = Updates.pull(QueryParams.CONFIGS_FILTERS.key(), new Document(FilterParams.NAME.key(), name));
QueryResult<UpdateResult> queryResult = userCollection.update(bsonQuery, update, null);
if (queryResult.first().getModifiedCount() == 0) {
throw new CatalogDBException("Internal error: Filter " + name + " could not be removed");
}
return endQuery("Delete filter", startTime, Arrays.asList(queryResult.first().getModifiedCount()));
}
@Override
public QueryResult<Long> count(Query query) throws CatalogDBException {
Bson bsonDocument = parseQuery(query);
return userCollection.count(bsonDocument);
}
@Override
public QueryResult distinct(Query query, String field) throws CatalogDBException {
Bson bsonDocument = parseQuery(query);
return userCollection.distinct(field, bsonDocument);
}
@Override
public QueryResult stats(Query query) {
return null;
}
@Override
public QueryResult<User> get(Query query, QueryOptions options) throws CatalogDBException {
if (!query.containsKey(QueryParams.STATUS_NAME.key())) {
query.append(QueryParams.STATUS_NAME.key(), "!=" + Status.TRASHED + ";!=" + Status.DELETED);
}
Bson bson = parseQuery(query);
QueryResult<User> userQueryResult = userCollection.find(bson, null, userConverter, options);
for (User user : userQueryResult.getResult()) {
if (user.getProjects() != null) {
List<Project> projects = new ArrayList<>(user.getProjects().size());
for (Project project : user.getProjects()) {
Query query1 = new Query(ProjectDBAdaptor.QueryParams.ID.key(), project.getId());
QueryResult<Project> projectQueryResult = dbAdaptorFactory.getCatalogProjectDbAdaptor().get(query1, options);
projects.add(projectQueryResult.first());
}
user.setProjects(projects);
}
}
return userQueryResult;
}
@Override
public QueryResult nativeGet(Query query, QueryOptions options) throws CatalogDBException {
if (!query.containsKey(QueryParams.STATUS_NAME.key())) {
query.append(QueryParams.STATUS_NAME.key(), "!=" + Status.TRASHED + ";!=" + Status.DELETED);
}
Bson bson = parseQuery(query);
QueryResult<Document> queryResult = userCollection.find(bson, options);
for (Document user : queryResult.getResult()) {
ArrayList<Document> projects = (ArrayList<Document>) user.get("projects");
if (projects.size() > 0) {
List<Document> projectsTmp = new ArrayList<>(projects.size());
for (Document project : projects) {
Query query1 = new Query(ProjectDBAdaptor.QueryParams.ID.key(), project.get(ProjectDBAdaptor
.QueryParams.ID.key()));
QueryResult<Document> queryResult1 = dbAdaptorFactory.getCatalogProjectDbAdaptor().nativeGet(query1, options);
projectsTmp.add(queryResult1.first());
}
user.remove("projects");
user.append("projects", projectsTmp);
}
}
return queryResult;
}
@Override
public QueryResult<Long> update(Query query, ObjectMap parameters) throws CatalogDBException {
long startTime = startQuery();
Map<String, Object> userParameters = new HashMap<>();
final String[] acceptedParams = {QueryParams.NAME.key(), QueryParams.EMAIL.key(), QueryParams.ORGANIZATION.key(),
QueryParams.LAST_MODIFIED.key(), };
filterStringParams(parameters, userParameters, acceptedParams);
if (parameters.containsKey(QueryParams.STATUS_NAME.key())) {
userParameters.put(QueryParams.STATUS_NAME.key(), parameters.get(QueryParams.STATUS_NAME.key()));
userParameters.put(QueryParams.STATUS_DATE.key(), TimeUtils.getTime());
}
final String[] acceptedLongParams = {QueryParams.QUOTA.key(), QueryParams.SIZE.key()};
filterLongParams(parameters, userParameters, acceptedLongParams);
final String[] acceptedMapParams = {QueryParams.ATTRIBUTES.key()};
filterMapParams(parameters, userParameters, acceptedMapParams);
if (!userParameters.isEmpty()) {
QueryResult<UpdateResult> update = userCollection.update(parseQuery(query),
new Document("$set", userParameters), null);
return endQuery("Update user", startTime, Arrays.asList(update.getNumTotalResults()));
}
return endQuery("Update user", startTime, new QueryResult<>());
}
@Override
public void delete(long id) throws CatalogDBException {
Query query = new Query(QueryParams.ID.key(), id);
delete(query);
}
@Override
public void delete(Query query) throws CatalogDBException {
QueryResult<DeleteResult> remove = userCollection.remove(parseQuery(query), null);
if (remove.first().getDeletedCount() == 0) {
throw CatalogDBException.deleteError("User");
}
}
@Override
public QueryResult<User> update(long id, ObjectMap parameters) throws CatalogDBException {
throw new NotImplementedException("Update user by int id. The id should be a string.");
}
public QueryResult<User> update(String userId, ObjectMap parameters) throws CatalogDBException {
long startTime = startQuery();
checkId(userId);
Query query = new Query(QueryParams.ID.key(), userId);
QueryResult<Long> update = update(query, parameters);
if (update.getResult().isEmpty() || update.first() != 1) {
throw new CatalogDBException("Could not update user " + userId);
}
return endQuery("Update user", startTime, get(query, null));
}
QueryResult<Long> setStatus(Query query, String status) throws CatalogDBException {
return update(query, new ObjectMap(QueryParams.STATUS_NAME.key(), status));
}
public QueryResult<User> setStatus(String userId, String status) throws CatalogDBException {
return update(userId, new ObjectMap(QueryParams.STATUS_NAME.key(), status));
}
@Override
public QueryResult<User> delete(long id, QueryOptions queryOptions) throws CatalogDBException {
throw new CatalogDBException("Delete user by int id. The id should be a string.");
}
public QueryResult<User> delete(String id, QueryOptions queryOptions) throws CatalogDBException {
long startTime = startQuery();
checkId(id);
// Check the user is active or banned
Query query = new Query(QueryParams.ID.key(), id)
.append(QueryParams.STATUS_NAME.key(), User.UserStatus.READY + "," + User.UserStatus.BANNED);
if (count(query).first() == 0) {
query.put(QueryParams.STATUS_NAME.key(), User.UserStatus.TRASHED + "," + User.UserStatus.DELETED);
QueryOptions options = new QueryOptions(MongoDBCollection.INCLUDE, QueryParams.STATUS_NAME.key());
User user = get(query, options).first();
throw new CatalogDBException("The user {" + id + "} was already " + user.getStatus().getName());
}
// If we don't find the force parameter, we check first if the user does not have an active project.
if (!queryOptions.containsKey(FORCE) || !queryOptions.getBoolean(FORCE)) {
checkCanDelete(id);
}
if (queryOptions.containsKey(FORCE) && queryOptions.getBoolean(FORCE)) {
// Delete the active projects (if any)
query = new Query(ProjectDBAdaptor.QueryParams.USER_ID.key(), id);
dbAdaptorFactory.getCatalogProjectDbAdaptor().delete(query, queryOptions);
}
// Change the status of the user to deleted
setStatus(id, User.UserStatus.TRASHED);
query = new Query(QueryParams.ID.key(), id)
.append(QueryParams.STATUS_NAME.key(), User.UserStatus.TRASHED);
return endQuery("Delete user", startTime, get(query, queryOptions));
}
/**
* Checks whether the userId has any active project.
*
* @param userId user id.
* @throws CatalogDBException when the user has active projects. Projects must be deleted first.
*/
private void checkCanDelete(String userId) throws CatalogDBException {
checkId(userId);
Query query = new Query(ProjectDBAdaptor.QueryParams.USER_ID.key(), userId)
.append(ProjectDBAdaptor.QueryParams.STATUS_NAME.key(), Status.READY);
Long count = dbAdaptorFactory.getCatalogProjectDbAdaptor().count(query).first();
if (count > 0) {
throw new CatalogDBException("The user {" + userId + "} cannot be deleted. The user has " + count + " projects in use.");
}
}
@Override
public QueryResult<Long> delete(Query query, QueryOptions queryOptions) throws CatalogDBException {
throw new UnsupportedOperationException("Remove not yet implemented.");
// long startTime = startQuery();
//
// List<User> userList = get(query, new QueryOptions()).getResult();
// List<Long> projectIds = new ArrayList<>();
// for (User user : userList) {
// for (Project project : user.getProjects()) {
// projectIds.add(project.getId());
// }
// }
//
// if (projectIds.size() > 0) {
// Query projectIdsQuery = new Query(CatalogProjectDBAdaptor.QueryParams.ID.key(), StringUtils.join(projectIds.toArray(), ","));
// dbAdaptorFactory.getCatalogProjectDbAdaptor().delete(projectIdsQuery, , force);
// }
//
// query.append(CatalogFileDBAdaptor.QueryParams.STATUS_NAME.key(), "!=" + Status.TRASHED + ";" + Status.DELETED);
// QueryResult<UpdateResult> deleted = userCollection.update(parseQuery(query), Updates.combine(Updates.set(
// QueryParams.STATUS_NAME.key(), Status.TRASHED), Updates.set(QueryParams.STATUS_DATE.key(), TimeUtils.getTimeMillis())),
// new QueryOptions());
//
// if (deleted.first().getModifiedCount() == 0) {
// throw CatalogDBException.deleteError("User");
// } else {
// return endQuery("Delete user", startTime, Collections.singletonList(deleted.first().getModifiedCount()));
// }
}
@Override
public QueryResult<User> remove(long id, QueryOptions queryOptions) throws CatalogDBException {
throw new UnsupportedOperationException("Remove not yet implemented.");
}
@Override
public QueryResult<Long> remove(Query query, QueryOptions queryOptions) throws CatalogDBException {
throw new UnsupportedOperationException("Remove not yet implemented.");
}
@Override
public QueryResult<Long> restore(Query query, QueryOptions queryOptions) throws CatalogDBException {
long startTime = startQuery();
query.put(QueryParams.STATUS_NAME.key(), Status.TRASHED);
return endQuery("Restore users", startTime, setStatus(query, Status.READY));
}
@Override
public QueryResult<User> restore(long id, QueryOptions queryOptions) throws CatalogDBException {
throw new CatalogDBException("Delete user by int id. The id should be a string.");
}
public QueryResult<User> restore(String id, QueryOptions queryOptions) throws CatalogDBException {
long startTime = startQuery();
checkId(id);
Query query = new Query(QueryParams.ID.key(), id)
.append(QueryParams.STATUS_NAME.key(), Status.TRASHED);
if (count(query).first() == 0) {
throw new CatalogDBException("The user {" + id + "} is not deleted");
}
setStatus(id, Status.READY);
query = new Query(QueryParams.ID.key(), id);
return endQuery("Restore user", startTime, get(query, null));
}
/***
* Removes completely the user from the database.
* @param id User id to be removed from the database.
* @return a QueryResult object with the user removed.
* @throws CatalogDBException when there is any problem during the removal.
*/
public QueryResult<User> clean(String id) throws CatalogDBException {
long startTime = startQuery();
Query query = new Query(QueryParams.ID.key(), id);
Bson bson = parseQuery(query);
QueryResult<User> userQueryResult = get(query, new QueryOptions());
QueryResult<DeleteResult> remove = userCollection.remove(bson, new QueryOptions());
if (remove.first().getDeletedCount() == 0) {
throw CatalogDBException.idNotFound("User", query.getString(QueryParams.ID.key()));
} else {
return endQuery("Clean user", startTime, userQueryResult);
}
}
@Override
public DBIterator<User> iterator(Query query, QueryOptions options) throws CatalogDBException {
Bson bson = parseQuery(query);
MongoCursor<Document> iterator = userCollection.nativeQuery().find(bson, options).iterator();
return new MongoDBIterator<>(iterator, userConverter);
}
@Override
public DBIterator<Document> nativeIterator(Query query, QueryOptions options) throws CatalogDBException {
Bson bson = parseQuery(query);
MongoCursor<Document> iterator = userCollection.nativeQuery().find(bson, options).iterator();
return new MongoDBIterator<>(iterator);
}
@Override
public QueryResult rank(Query query, String field, int numResults, boolean asc) throws CatalogDBException {
Bson bsonQuery = parseQuery(query);
return rank(userCollection, bsonQuery, field, "name", numResults, asc);
}
@Override
public QueryResult groupBy(Query query, String field, QueryOptions options) throws CatalogDBException {
Bson bsonQuery = parseQuery(query);
return groupBy(userCollection, bsonQuery, field, "name", options);
}
@Override
public QueryResult groupBy(Query query, List<String> fields, QueryOptions options) throws CatalogDBException {
Bson bsonQuery = parseQuery(query);
return groupBy(userCollection, bsonQuery, fields, "name", options);
}
@Override
public void forEach(Query query, Consumer<? super Object> action, QueryOptions options) throws CatalogDBException {
Objects.requireNonNull(action);
DBIterator<User> catalogDBIterator = iterator(query, options);
while (catalogDBIterator.hasNext()) {
action.accept(catalogDBIterator.next());
}
catalogDBIterator.close();
}
private Bson parseQuery(Query query) throws CatalogDBException {
List<Bson> andBsonList = new ArrayList<>();
for (Map.Entry<String, Object> entry : query.entrySet()) {
String key = entry.getKey().split("\\.")[0];
QueryParams queryParam = QueryParams.getParam(entry.getKey()) != null ? QueryParams.getParam(entry.getKey())
: QueryParams.getParam(key);
if (queryParam == null) {
continue;
}
try {
switch (queryParam) {
case ID:
addOrQuery(PRIVATE_ID, queryParam.key(), query, queryParam.type(), andBsonList);
break;
case ATTRIBUTES:
addAutoOrQuery(entry.getKey(), entry.getKey(), query, queryParam.type(), andBsonList);
break;
case BATTRIBUTES:
String mongoKey = entry.getKey().replace(QueryParams.BATTRIBUTES.key(), QueryParams.ATTRIBUTES.key());
addAutoOrQuery(mongoKey, entry.getKey(), query, queryParam.type(), andBsonList);
break;
case NATTRIBUTES:
mongoKey = entry.getKey().replace(QueryParams.NATTRIBUTES.key(), QueryParams.ATTRIBUTES.key());
addAutoOrQuery(mongoKey, entry.getKey(), query, queryParam.type(), andBsonList);
break;
case NAME:
case EMAIL:
case PASSWORD:
case ORGANIZATION:
case STATUS_NAME:
case STATUS_MSG:
case STATUS_DATE:
case LAST_MODIFIED:
case SIZE:
case QUOTA:
case PROJECTS:
case PROJECT_ID:
case PROJECT_NAME:
case PROJECT_ALIAS:
case PROJECT_ORGANIZATION:
case PROJECT_STATUS:
case PROJECT_LAST_MODIFIED:
case TOOL_ID:
case TOOL_NAME:
case TOOL_ALIAS:
case SESSIONS:
case SESSION_ID:
case SESSION_IP:
case SESSION_LOGIN:
case SESSION_LOGOUT:
case CONFIGS:
case CONFIGS_FILTERS:
case CONFIGS_FILTERS_NAME:
addAutoOrQuery(queryParam.key(), queryParam.key(), query, queryParam.type(), andBsonList);
break;
default:
break;
}
} catch (Exception e) {
throw new CatalogDBException(e);
}
}
if (andBsonList.size() > 0) {
return Filters.and(andBsonList);
} else {
return new Document();
}
}
public MongoDBCollection getUserCollection() {
return userCollection;
}
}