/* * 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.managers; import org.apache.commons.lang3.NotImplementedException; 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.audit.AuditManager; import org.opencb.opencga.catalog.audit.AuditRecord; import org.opencb.opencga.catalog.auth.authorization.AuthorizationManager; import org.opencb.opencga.catalog.config.Configuration; import org.opencb.opencga.catalog.db.DBAdaptorFactory; import org.opencb.opencga.catalog.db.api.*; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogIOException; import org.opencb.opencga.catalog.io.CatalogIOManager; import org.opencb.opencga.catalog.io.CatalogIOManagerFactory; import org.opencb.opencga.catalog.managers.api.IStudyManager; import org.opencb.opencga.catalog.models.*; import org.opencb.opencga.catalog.models.acls.permissions.DiseasePanelAclEntry; import org.opencb.opencga.catalog.models.acls.permissions.StudyAclEntry; import org.opencb.opencga.catalog.models.summaries.StudySummary; import org.opencb.opencga.catalog.models.summaries.VariableSetSummary; import org.opencb.opencga.catalog.models.summaries.VariableSummary; import org.opencb.opencga.catalog.utils.CatalogAnnotationsValidator; import org.opencb.opencga.catalog.utils.ParamUtils; import org.opencb.opencga.core.common.TimeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.io.IOException; import java.net.URI; import java.util.*; import java.util.stream.Collectors; /** * @author Jacobo Coll <jacobo167@gmail.com> */ public class StudyManager extends AbstractManager implements IStudyManager { protected static Logger logger = LoggerFactory.getLogger(StudyManager.class); @Deprecated public StudyManager(AuthorizationManager authorizationManager, AuditManager auditManager, DBAdaptorFactory catalogDBAdaptorFactory, CatalogIOManagerFactory ioManagerFactory, Properties catalogProperties) { super(authorizationManager, auditManager, catalogDBAdaptorFactory, ioManagerFactory, catalogProperties); } public StudyManager(AuthorizationManager authorizationManager, AuditManager auditManager, CatalogManager catalogManager, DBAdaptorFactory catalogDBAdaptorFactory, CatalogIOManagerFactory ioManagerFactory, Configuration configuration) { super(authorizationManager, auditManager, catalogManager, catalogDBAdaptorFactory, ioManagerFactory, configuration); } @Override public String getUserId(long studyId) throws CatalogException { return studyDBAdaptor.getOwnerId(studyId); } @Override public Long getProjectId(long studyId) throws CatalogException { return studyDBAdaptor.getProjectIdByStudyId(studyId); } public List<Long> getIds(String userId, String studyStr) throws CatalogException { if (StringUtils.isNumeric(studyStr)) { long studyId = Long.parseLong(studyStr); if (studyId > configuration.getCatalog().getOffset()) { studyDBAdaptor.checkId(studyId); return Arrays.asList(studyId); } } Query query = new Query(); final QueryOptions queryOptions = new QueryOptions(QueryOptions.INCLUDE, StudyDBAdaptor.QueryParams.ID.key()); if (StringUtils.isEmpty(studyStr)) { if (!userId.equals("anonymous")) { // Obtain the projects of the user QueryOptions options = new QueryOptions(QueryOptions.INCLUDE, ProjectDBAdaptor.QueryParams.ID.key()); QueryResult<Project> projectQueryResult = projectDBAdaptor.get(userId, options); if (projectQueryResult.getNumResults() == 1) { projectDBAdaptor.checkId(projectQueryResult.first().getId()); query.put(StudyDBAdaptor.QueryParams.PROJECT_ID.key(), projectQueryResult.first().getId()); } else { if (projectQueryResult.getNumResults() == 0) { throw new CatalogException("No projects found for user " + userId); } else { throw new CatalogException("More than one project found for user " + userId); } } } else { // Anonymous user // 1. Check if the anonymous user has been given permissions in any study query.append(StudyDBAdaptor.QueryParams.ACL_MEMBER.key(), "anonymous"); query.append(StudyDBAdaptor.QueryParams.ACL_PERMISSIONS.key(), StudyAclEntry.StudyPermissions.VIEW_STUDY); } QueryResult<Study> studyQueryResult = studyDBAdaptor.get(query, queryOptions); if (studyQueryResult.getNumResults() == 0) { throw new CatalogException("No studies found for user " + userId); } else { return studyQueryResult.getResult().stream().map(study -> study.getId()).collect(Collectors.toList()); } } else { String[] split = studyStr.split(":"); List<Long> projectIds; if (split.length > 2) { throw new CatalogException("More than one : separator found. Format: [[user@]project:]study"); } String aliasStudy; String aliasProject = null; if (split.length == 2) { aliasStudy = split[1]; aliasProject = split[0]; } else { aliasStudy = studyStr; } List<Long> retStudies = new ArrayList<>(); List<String> aliasList = new ArrayList<>(); if (!aliasStudy.equals("*")) { // Check if there is more than one study listed in aliasStudy String[] split1 = aliasStudy.split(","); for (String studyStrAux : split1) { if (StringUtils.isNumeric(studyStrAux)) { retStudies.add(Long.parseLong(studyStrAux)); } else { aliasList.add(studyStrAux); } } } if (aliasList.size() == 0 && retStudies.size() > 0) { // The list of provided studies were all long ids return retStudies; } if (!userId.equals("anonymous")) { if (aliasProject != null) { projectIds = Arrays.asList(catalogManager.getProjectManager().getId(userId, aliasProject)); } else { // Obtain the projects of the user QueryOptions options = new QueryOptions(QueryOptions.INCLUDE, ProjectDBAdaptor.QueryParams.ID.key()); QueryResult<Project> projectQueryResult = projectDBAdaptor.get(userId, options); if (projectQueryResult.getNumResults() == 0) { throw new CatalogException("No projects found for user " + userId); } else { projectIds = projectQueryResult.getResult().stream().map(project -> project.getId()).collect(Collectors.toList()); } } query.put(StudyDBAdaptor.QueryParams.PROJECT_ID.key(), projectIds); } else { // Anonymous user if (aliasProject != null) { projectIds = catalogManager.getProjectManager().getIds(userId, aliasProject); query.put(StudyDBAdaptor.QueryParams.PROJECT_ID.key(), projectIds); } // Add permissions for user anonymous in the query query.append(StudyDBAdaptor.QueryParams.ACL_MEMBER.key(), "anonymous"); query.append(StudyDBAdaptor.QueryParams.ACL_PERMISSIONS.key(), StudyAclEntry.StudyPermissions.VIEW_STUDY); } if (aliasList.size() > 0) { // This if is justified by the fact that we might not have any alias or id but an * query.put(StudyDBAdaptor.QueryParams.ALIAS.key(), aliasList); } QueryResult<Study> studyQueryResult = studyDBAdaptor.get(query, queryOptions); if (studyQueryResult.getNumResults() == 0) { throw new CatalogException("No studies found for user " + userId); } else { if (aliasList.size() > 0 && studyQueryResult.getNumResults() != aliasList.size()) { throw new CatalogException("Not all the studies were found. Found " + studyQueryResult.getNumResults() + " out of " + aliasList.size()); } else { retStudies.addAll(studyQueryResult.getResult().stream().map(study -> study.getId()).collect(Collectors.toList())); return retStudies; } } } } @Override public Long getId(String userId, String studyStr) throws CatalogException { logger.debug("user {}, study {}", userId, studyStr); if (studyStr != null && studyStr.contains(",")) { throw new CatalogException("Only one study is allowed. More than one study found in " + studyStr); } List<Long> ids = getIds(userId, studyStr); if (ids.size() > 1) { throw new CatalogException("More than one study was found for study '" + studyStr + '\''); } else { return ids.get(0); } } @Deprecated @Override public Long getId(String studyId) throws CatalogException { if (StringUtils.isNumeric(studyId)) { return Long.parseLong(studyId); } String[] split = studyId.split("@"); if (split.length != 2) { return -1L; } String[] projectStudy = split[1].replace(':', '/').split("/", 2); if (projectStudy.length != 2) { return -2L; } long projectId = projectDBAdaptor.getId(split[0], projectStudy[0]); return studyDBAdaptor.getId(projectId, projectStudy[1]); } @Override public QueryResult<Study> create(long projectId, String name, String alias, Study.Type type, String creationDate, String description, Status status, String cipher, String uriScheme, URI uri, Map<File.Bioformat, DataStore> datastores, Map<String, Object> stats, Map<String, Object> attributes, QueryOptions options, String sessionId) throws CatalogException { ParamUtils.checkParameter(name, "name"); ParamUtils.checkParameter(alias, "alias"); ParamUtils.checkObj(type, "type"); ParamUtils.checkAlias(alias, "alias", configuration.getCatalog().getOffset()); String userId = catalogManager.getUserManager().getId(sessionId); description = ParamUtils.defaultString(description, ""); // creatorId = ParamUtils.defaultString(creatorId, userId); creationDate = ParamUtils.defaultString(creationDate, TimeUtils.getTime()); status = ParamUtils.defaultObject(status, Status::new); cipher = ParamUtils.defaultString(cipher, "none"); if (uri != null) { if (uri.getScheme() == null) { throw new CatalogException("StudyUri must specify the scheme"); } else { if (uriScheme != null && !uriScheme.isEmpty()) { if (!uriScheme.equals(uri.getScheme())) { throw new CatalogException("StudyUri must specify the scheme"); } } else { uriScheme = uri.getScheme(); } } } else { uriScheme = catalogIOManagerFactory.getDefaultCatalogScheme(); } datastores = ParamUtils.defaultObject(datastores, HashMap<File.Bioformat, DataStore>::new); stats = ParamUtils.defaultObject(stats, HashMap<String, Object>::new); attributes = ParamUtils.defaultObject(attributes, HashMap<String, Object>::new); CatalogIOManager catalogIOManager = catalogIOManagerFactory.get(uriScheme); // String projectOwnerId = projectDBAdaptor.getProjectOwnerId(projectId); /* Check project permissions */ if (!projectDBAdaptor.getOwnerId(projectId).equals(userId)) { throw new CatalogException("Permission denied: Only the owner of the project can create studies."); } LinkedList<File> files = new LinkedList<>(); LinkedList<Experiment> experiments = new LinkedList<>(); LinkedList<Job> jobs = new LinkedList<>(); File rootFile = new File(".", File.Type.DIRECTORY, null, null, "", "study root folder", new File.FileStatus(File.FileStatus.READY), 0); files.add(rootFile); // We set all the permissions for the owner of the study. // StudyAcl studyAcl = new StudyAcl(userId, AuthorizationManager.getAdminAcls()); Study study = new Study(-1, name, alias, type, creationDate, description, status, TimeUtils.getTime(), 0, cipher, new LinkedList<>(), new LinkedList<>(), experiments, files, jobs, new LinkedList<>(), new LinkedList<>(), new LinkedList<>(), new LinkedList<>(), Collections.emptyList(), new LinkedList<>(), null, datastores, stats, attributes); /* CreateStudy */ QueryResult<Study> result = studyDBAdaptor.insert(projectId, study, options); study = result.getResult().get(0); //URI studyUri; if (uri == null) { try { uri = catalogIOManager.createStudy(userId, Long.toString(projectId), Long.toString(study.getId())); } catch (CatalogIOException e) { try { studyDBAdaptor.delete(study.getId()); } catch (Exception e1) { logger.error("Can't delete study after failure creating study", e1); } throw e; } } study = studyDBAdaptor.update(study.getId(), new ObjectMap("uri", uri)).first(); // auditManager.recordCreation(AuditRecord.Resource.study, study.getId(), userId, study, null, null); auditManager.recordAction(AuditRecord.Resource.study, AuditRecord.Action.create, AuditRecord.Magnitude.low, study.getId(), userId, null, study, null, null); long rootFileId = fileDBAdaptor.getId(study.getId(), ""); //Set studyUri to the root folder too rootFile = fileDBAdaptor.update(rootFileId, new ObjectMap("uri", uri)).first(); // auditManager.recordCreation(AuditRecord.Resource.file, rootFile.getId(), userId, rootFile, null, null); auditManager.recordAction(AuditRecord.Resource.file, AuditRecord.Action.create, AuditRecord.Magnitude.low, rootFile.getId(), userId, null, rootFile, null, null); userDBAdaptor.updateUserLastModified(userId); return result; } @Deprecated @Override public QueryResult<Study> share(long studyId, AclEntry acl) throws CatalogException { throw new UnsupportedOperationException(); } @Override public QueryResult<Study> get(Long studyId, QueryOptions options, String sessionId) throws CatalogException { options = ParamUtils.defaultObject(options, QueryOptions::new); String userId = catalogManager.getUserManager().getId(sessionId); studyDBAdaptor.checkId(studyId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.VIEW_STUDY); QueryResult<Study> studyResult = studyDBAdaptor.get(studyId, options); if (!studyResult.getResult().isEmpty()) { authorizationManager.filterFiles(userId, studyId, studyResult.getResult().get(0).getFiles()); } return studyResult; } @Override public QueryResult<Study> get(Query query, QueryOptions options, String sessionId) throws CatalogException { query = ParamUtils.defaultObject(query, Query::new); QueryOptions qOptions = options != null ? new QueryOptions(options) : new QueryOptions(); String userId = catalogManager.getUserManager().getId(sessionId); if (!qOptions.containsKey("include") || qOptions.get("include") == null || qOptions.getAsStringList("include").isEmpty()) { qOptions.addToListOption("exclude", "projects.studies.attributes.studyConfiguration"); } QueryResult<Study> allStudies = studyDBAdaptor.get(query, qOptions); List<Study> studies = allStudies.getResult(); authorizationManager.filterStudies(userId, studies); allStudies.setResult(studies); allStudies.setNumResults(studies.size()); return allStudies; } @Override public QueryResult<Study> update(Long studyId, ObjectMap parameters, QueryOptions options, String sessionId) throws CatalogException { ParamUtils.checkObj(parameters, "Parameters"); ParamUtils.checkId(studyId, "studyId"); String userId = catalogManager.getUserManager().getId(sessionId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.UPDATE_STUDY); if (parameters.containsKey("alias")) { rename(studyId, parameters.getString("alias"), sessionId); //Clone and remove alias from parameters. Do not modify the original parameter parameters = new ObjectMap(parameters); parameters.remove("alias"); } for (String s : parameters.keySet()) { if (!s.matches("name|type|description|attributes|stats")) { throw new CatalogDBException("Parameter '" + s + "' can't be changed"); } } String ownerId = studyDBAdaptor.getOwnerId(studyId); userDBAdaptor.updateUserLastModified(ownerId); QueryResult<Study> result = studyDBAdaptor.update(studyId, parameters); auditManager.recordUpdate(AuditRecord.Resource.study, studyId, userId, parameters, null, null); return result; } private QueryResult rename(long studyId, String newStudyAlias, String sessionId) throws CatalogException { ParamUtils.checkAlias(newStudyAlias, "newStudyAlias", configuration.getCatalog().getOffset()); String userId = catalogManager.getUserManager().getId(sessionId); // String studyOwnerId = studyDBAdaptor.getStudyOwnerId(studyId); //User can't write/modify the study authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.UPDATE_STUDY); // Both users must bu updated userDBAdaptor.updateUserLastModified(userId); // userDBAdaptor.updateUserLastModified(studyOwnerId); //TODO get all shared users to updateUserLastModified //QueryResult queryResult = studyDBAdaptor.renameStudy(studyId, newStudyAlias); auditManager.recordUpdate(AuditRecord.Resource.study, studyId, userId, new ObjectMap("alias", newStudyAlias), null, null); return new QueryResult(); } @Override public List<QueryResult<Study>> delete(String ids, QueryOptions options, String sessionId) throws CatalogException { throw new UnsupportedOperationException(); } @Override public List<QueryResult<Study>> delete(Query query, QueryOptions options, String sessionId) throws CatalogException, IOException { throw new UnsupportedOperationException(); } @Override public List<QueryResult<Study>> restore(String ids, QueryOptions options, String sessionId) throws CatalogException { throw new UnsupportedOperationException(); } @Override public List<QueryResult<Study>> restore(Query query, QueryOptions options, String sessionId) throws CatalogException { throw new UnsupportedOperationException(); } @Override public void setStatus(String id, String status, String message, String sessionId) throws CatalogException { throw new NotImplementedException("Project: Operation not yet supported"); } @Override public QueryResult rank(long projectId, Query query, String field, int numResults, boolean asc, String sessionId) throws CatalogException { query = ParamUtils.defaultObject(query, Query::new); ParamUtils.checkObj(field, "field"); ParamUtils.checkObj(projectId, "projectId"); String userId = catalogManager.getUserManager().getId(sessionId); authorizationManager.checkProjectPermission(projectId, userId, StudyAclEntry.StudyPermissions.VIEW_STUDY); // TODO: In next release, we will have to check the count parameter from the queryOptions object. boolean count = true; // query.append(CatalogFileDBAdaptor.QueryParams.STUDY_ID.key(), studyId); QueryResult queryResult = null; if (count) { // We do not need to check for permissions when we show the count of files queryResult = studyDBAdaptor.rank(query, field, numResults, asc); } return ParamUtils.defaultObject(queryResult, QueryResult::new); } @Override public QueryResult groupBy(long projectId, Query query, String field, QueryOptions options, String sessionId) throws CatalogException { query = ParamUtils.defaultObject(query, Query::new); options = ParamUtils.defaultObject(options, QueryOptions::new); ParamUtils.checkObj(field, "field"); ParamUtils.checkObj(projectId, "projectId"); String userId = catalogManager.getUserManager().getId(sessionId); authorizationManager.checkProjectPermission(projectId, userId, StudyAclEntry.StudyPermissions.VIEW_STUDY); // TODO: In next release, we will have to check the count parameter from the queryOptions object. boolean count = true; QueryResult queryResult = null; if (count) { // We do not need to check for permissions when we show the count of files queryResult = studyDBAdaptor.groupBy(query, field, options); } return ParamUtils.defaultObject(queryResult, QueryResult::new); } @Override public QueryResult groupBy(long projectId, Query query, List<String> fields, QueryOptions options, String sessionId) throws CatalogException { query = ParamUtils.defaultObject(query, Query::new); options = ParamUtils.defaultObject(options, QueryOptions::new); ParamUtils.checkObj(fields, "fields"); ParamUtils.checkObj(projectId, "projectId"); String userId = catalogManager.getUserManager().getId(sessionId); authorizationManager.checkProjectPermission(projectId, userId, StudyAclEntry.StudyPermissions.VIEW_STUDY); // TODO: In next release, we will have to check the count parameter from the queryOptions object. boolean count = true; QueryResult queryResult = null; if (count) { // We do not need to check for permissions when we show the count of files queryResult = studyDBAdaptor.groupBy(query, fields, options); } return ParamUtils.defaultObject(queryResult, QueryResult::new); } @Override public QueryResult<StudySummary> getSummary(long studyId, String sessionId, QueryOptions queryOptions) throws CatalogException { long startTime = System.currentTimeMillis(); String userId = catalogManager.getUserManager().getId(sessionId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.VIEW_STUDY); Study studyInfo = get(studyId, queryOptions, sessionId).first(); StudySummary studySummary = new StudySummary() .setAlias(studyInfo.getAlias()) .setAttributes(studyInfo.getAttributes()) .setCipher(studyInfo.getCipher()) .setCreationDate(studyInfo.getCreationDate()) .setDatasets(studyInfo.getDatasets().size()) .setDescription(studyInfo.getDescription()) .setDiskUsage(studyInfo.getSize()) .setExperiments(studyInfo.getExperiments()) .setGroups(studyInfo.getGroups()) .setName(studyInfo.getName()) .setStats(studyInfo.getStats()) .setStatus(studyInfo.getStatus()) .setType(studyInfo.getType()) .setVariableSets(studyInfo.getVariableSets()); Long nFiles = fileDBAdaptor.count( new Query(FileDBAdaptor.QueryParams.STUDY_ID.key(), studyId) .append(FileDBAdaptor.QueryParams.TYPE.key(), File.Type.FILE) .append(FileDBAdaptor.QueryParams.STATUS_NAME.key(), "!=" + File.FileStatus.TRASHED + ";!=" + File.FileStatus.DELETED)) .first(); studySummary.setFiles(nFiles); Long nSamples = sampleDBAdaptor.count( new Query(SampleDBAdaptor.QueryParams.STUDY_ID.key(), studyId) .append(SampleDBAdaptor.QueryParams.STATUS_NAME.key(), "!=" + File.FileStatus.TRASHED + ";!=" + File.FileStatus.DELETED)) .first(); studySummary.setSamples(nSamples); Long nJobs = jobDBAdaptor.count( new Query(JobDBAdaptor.QueryParams.STUDY_ID.key(), studyId) .append(JobDBAdaptor.QueryParams.STATUS_NAME.key(), "!=" + File.FileStatus.TRASHED + ";!=" + File.FileStatus.DELETED)) .first(); studySummary.setJobs(nJobs); Long nCohorts = cohortDBAdaptor.count( new Query(CohortDBAdaptor.QueryParams.STUDY_ID.key(), studyId) .append(CohortDBAdaptor.QueryParams.STATUS_NAME.key(), "!=" + File.FileStatus.TRASHED + ";!=" + File.FileStatus.DELETED)) .first(); studySummary.setCohorts(nCohorts); Long nIndividuals = individualDBAdaptor.count( new Query(IndividualDBAdaptor.QueryParams.STUDY_ID.key(), studyId) .append(IndividualDBAdaptor.QueryParams.STATUS_NAME.key(), "!=" + File.FileStatus.TRASHED + ";!=" + File.FileStatus.DELETED)) .first(); studySummary.setIndividuals(nIndividuals); return new QueryResult<>("Study summary", (int) (System.currentTimeMillis() - startTime), 1, 1, "", "", Collections.singletonList(studySummary)); } @Deprecated @Override public QueryResult<StudyAclEntry> getAcls(String studyStr, List<String> members, String sessionId) throws CatalogException { long startTime = System.currentTimeMillis(); String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(userId, studyStr); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.SHARE_STUDY); // Split and obtain the set of members (users + groups), users and groups Set<String> memberSet = new HashSet<>(); Set<String> userIds = new HashSet<>(); Set<String> groupIds = new HashSet<>(); for (String member: members) { memberSet.add(member); if (!member.startsWith("@")) { userIds.add(member); } else { groupIds.add(member); } } // Obtain the groups the user might belong to in order to be able to get the permissions properly // (the permissions might be given to the group instead of the user) // Map of group -> users Map<String, List<String>> groupUsers = new HashMap<>(); if (userIds.size() > 0) { List<String> tmpUserIds = userIds.stream().collect(Collectors.toList()); QueryResult<Group> groups = studyDBAdaptor.getGroup(studyId, null, tmpUserIds); // We add the groups where the users might belong to to the memberSet if (groups.getNumResults() > 0) { for (Group group : groups.getResult()) { for (String tmpUserId : group.getUserIds()) { if (userIds.contains(tmpUserId)) { memberSet.add(group.getName()); if (!groupUsers.containsKey(group.getName())) { groupUsers.put(group.getName(), new ArrayList<>()); } groupUsers.get(group.getName()).add(tmpUserId); } } } } } List<String> memberList = memberSet.stream().collect(Collectors.toList()); QueryResult<StudyAclEntry> studyAclQueryResult = studyDBAdaptor.getAcl(studyId, memberList); if (members.size() == 0) { return studyAclQueryResult; } // For the cases where the permissions were given at group level, we obtain the user and return it as if they were given to the user // instead of the group. Map<String, StudyAclEntry> studyAclHashMap = new HashMap<>(); for (StudyAclEntry studyAcl : studyAclQueryResult.getResult()) { String tmpMember = studyAcl.getMember(); if (memberList.contains(tmpMember)) { if (tmpMember.startsWith("@")) { // Check if the user was demanding the group directly or a user belonging to the group if (groupIds.contains(tmpMember)) { studyAclHashMap.put(tmpMember, studyAcl); } else { // Obtain the user(s) belonging to that group whose permissions wanted the userId if (groupUsers.containsKey(tmpMember)) { for (String tmpUserId : groupUsers.get(tmpMember)) { if (userIds.contains(tmpUserId)) { studyAclHashMap.put(tmpUserId, new StudyAclEntry(tmpUserId, studyAcl.getPermissions())); } } } } } else { // Add the user studyAclHashMap.put(tmpMember, studyAcl); } } } // We recreate the output that is in studyAclHashMap but in the same order the members were queried. List<StudyAclEntry> studyAclList = new ArrayList<>(studyAclHashMap.size()); for (String member : members) { if (studyAclHashMap.containsKey(member)) { studyAclList.add(studyAclHashMap.get(member)); } } // Update queryResult info studyAclQueryResult.setId(studyStr); studyAclQueryResult.setNumResults(studyAclList.size()); studyAclQueryResult.setDbTime((int) (System.currentTimeMillis() - startTime)); studyAclQueryResult.setResult(studyAclList); return studyAclQueryResult; } @Override public QueryResult<Group> createGroup(String studyStr, String groupId, String users, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(userId, studyStr); studyDBAdaptor.checkId(studyId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.SHARE_STUDY); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.UPDATE_STUDY); // Fix the groupId if (!groupId.startsWith("@")) { groupId = "@" + groupId; } // Create the list of users List<String> userList; if (users != null && !users.isEmpty()) { userList = Arrays.asList(users.split(",")); } else { userList = Collections.emptyList(); } // Check group exists if (existsGroup(studyId, groupId)) { throw new CatalogException("The group " + groupId + " already exists."); } // Check the list of users is ok for (String user : userList) { userDBAdaptor.checkId(user); } // Check that none of the users belong to other group StringBuilder errorMessage = new StringBuilder("Cannot create group. These users already belong to other group: "); boolean errorFlag = false; for (String user : userList) { if (memberBelongsToGroup(studyId, user)) { errorMessage.append(user).append(","); errorFlag = true; } } if (errorFlag) { throw new CatalogException(errorMessage.toString()); } // Create the group return studyDBAdaptor.createGroup(studyId, groupId, userList); } private boolean existsGroup(long studyId, String groupId) throws CatalogDBException { Query query = new Query() .append(StudyDBAdaptor.QueryParams.ID.key(), studyId) .append(StudyDBAdaptor.QueryParams.GROUP_NAME.key(), groupId); return studyDBAdaptor.count(query).first() > 0; } private boolean memberBelongsToGroup(long studyId, String member) throws CatalogDBException { Query query = new Query() .append(StudyDBAdaptor.QueryParams.ID.key(), studyId) .append(StudyDBAdaptor.QueryParams.GROUP_USER_IDS.key(), member); return studyDBAdaptor.count(query).first() > 0; } @Override public QueryResult<Group> getAllGroups(String studyStr, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(userId, studyStr); studyDBAdaptor.checkId(studyId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.SHARE_STUDY); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.UPDATE_STUDY); Query query = new Query(StudyDBAdaptor.QueryParams.ID.key(), studyId); QueryOptions queryOptions = new QueryOptions(QueryOptions.INCLUDE, StudyDBAdaptor.QueryParams.GROUPS.key()); QueryResult<Study> studyQueryResult = studyDBAdaptor.get(query, queryOptions); List<Group> groupList; if (studyQueryResult != null && studyQueryResult.getNumResults() == 1) { groupList = studyQueryResult.first().getGroups(); } else { groupList = Collections.emptyList(); } return new QueryResult<>("Get all groups", studyQueryResult.getDbTime(), groupList.size(), groupList.size(), studyQueryResult.getWarningMsg(), studyQueryResult.getErrorMsg(), groupList); } @Override public QueryResult<Group> getGroup(String studyStr, String groupId, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(userId, studyStr); studyDBAdaptor.checkId(studyId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.SHARE_STUDY); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.UPDATE_STUDY); // Fix the groupId if (!groupId.startsWith("@")) { groupId = "@" + groupId; } return studyDBAdaptor.getGroup(studyId, groupId, Collections.emptyList()); } @Override public QueryResult<Group> updateGroup(String studyStr, String groupId, @Nullable String addUsers, @Nullable String removeUsers, @Nullable String setUsers, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(userId, studyStr); studyDBAdaptor.checkId(studyId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.SHARE_STUDY); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.UPDATE_STUDY); // Fix the groupId if (!groupId.startsWith("@")) { groupId = "@" + groupId; } // Check the group exists Query query = new Query() .append(StudyDBAdaptor.QueryParams.ID.key(), studyId) .append(StudyDBAdaptor.QueryParams.GROUP_NAME.key(), groupId); if (studyDBAdaptor.count(query).first() == 0) { throw new CatalogException("The group " + groupId + " does not exist."); } List<String> userList; if (StringUtils.isNotEmpty(setUsers)) { userList = Arrays.asList(setUsers.split(",")); studyDBAdaptor.setUsersToGroup(studyId, groupId, userList); } else { if (StringUtils.isNotEmpty(addUsers)) { userList = Arrays.asList(addUsers.split(",")); studyDBAdaptor.addUsersToGroup(studyId, groupId, userList); } if (StringUtils.isNotEmpty(removeUsers)) { userList = Arrays.asList(removeUsers.split(",")); studyDBAdaptor.removeUsersFromGroup(studyId, groupId, userList); } } return studyDBAdaptor.getGroup(studyId, groupId, Collections.emptyList()); } @Override public QueryResult<Group> deleteGroup(String studyStr, String groupId, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(userId, studyStr); studyDBAdaptor.checkId(studyId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.SHARE_STUDY); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.UPDATE_STUDY); // Fix the groupId if (!groupId.startsWith("@")) { groupId = "@" + groupId; } QueryResult<Group> group = studyDBAdaptor.getGroup(studyId, groupId, Collections.emptyList()); group.setId("Delete group"); studyDBAdaptor.deleteGroup(studyId, groupId); // Remove the permissions the group might have had if (authorizationManager.memberHasPermissionsInStudy(studyId, groupId)) { authorizationManager.removeStudyAcl(userId, studyId, groupId); } return group; } @Override public Long getDiseasePanelId(String userId, String panelStr) throws CatalogException { if (StringUtils.isNumeric(panelStr)) { return Long.parseLong(panelStr); } // Resolve the studyIds and filter the panelName ObjectMap parsedPanelStr = parseFeatureId(userId, panelStr); List<Long> studyIds = getStudyIds(parsedPanelStr); String panelName = parsedPanelStr.getString("featureName"); Query query = new Query(PanelDBAdaptor.QueryParams.STUDY_ID.key(), studyIds) .append(PanelDBAdaptor.QueryParams.NAME.key(), panelName); QueryOptions qOptions = new QueryOptions(QueryOptions.INCLUDE, "projects.studies.panels.id"); QueryResult<DiseasePanel> queryResult = panelDBAdaptor.get(query, qOptions); if (queryResult.getNumResults() > 1) { throw new CatalogException("Error: More than one panel id found based on " + panelName); } else if (queryResult.getNumResults() == 0) { return -1L; } else { return queryResult.first().getId(); } } @Override public QueryResult<DiseasePanel> createDiseasePanel(String studyStr, String name, String disease, String description, String genes, String regions, String variants, QueryOptions options, String sessionId) throws CatalogException { ParamUtils.checkParameter(name, "name"); String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(studyStr); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.WRITE_PANELS); ParamUtils.checkParameter(disease, "disease"); description = ParamUtils.defaultString(description, ""); List<String> geneList = Collections.emptyList(); List<String> regionList = Collections.emptyList(); List<String> variantList = Collections.emptyList(); if (genes != null) { geneList = Arrays.asList(genes.split(",")); } if (regions != null) { regionList = Arrays.asList(regions.split(",")); } if (variants != null) { variantList = Arrays.asList(variants.split(",")); } if (geneList.size() == 0 && regionList.size() == 0 && variantList.size() == 0) { throw new CatalogException("Cannot create a new disease panel with no genes, regions and variants. At least, one of them should" + " be provided."); } DiseasePanel diseasePanel = new DiseasePanel(-1, name, disease, description, geneList, regionList, variantList, new DiseasePanel.PanelStatus()); QueryResult<DiseasePanel> queryResult = panelDBAdaptor.insert(diseasePanel, studyId, options); // auditManager.recordCreation(AuditRecord.Resource.panel, queryResult.first().getId(), userId, queryResult.first(), null, null); auditManager.recordAction(AuditRecord.Resource.panel, AuditRecord.Action.create, AuditRecord.Magnitude.low, queryResult.first().getId(), userId, null, queryResult.first(), null, null); return queryResult; } @Override public QueryResult<DiseasePanel> getDiseasePanel(String panelStr, QueryOptions options, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); Long panelId = getDiseasePanelId(userId, panelStr); authorizationManager.checkDiseasePanelPermission(panelId, userId, DiseasePanelAclEntry.DiseasePanelPermissions.VIEW); QueryResult<DiseasePanel> queryResult = panelDBAdaptor.get(panelId, options); return queryResult; } @Override public QueryResult<DiseasePanel> updateDiseasePanel(String panelStr, ObjectMap parameters, String sessionId) throws CatalogException { ParamUtils.checkObj(parameters, "Parameters"); String userId = catalogManager.getUserManager().getId(sessionId); Long diseasePanelId = getDiseasePanelId(userId, panelStr); authorizationManager.checkDiseasePanelPermission(diseasePanelId, userId, DiseasePanelAclEntry.DiseasePanelPermissions.UPDATE); for (String s : parameters.keySet()) { if (!s.matches("name|disease")) { throw new CatalogDBException("Parameter '" + s + "' can't be changed"); } } QueryResult<DiseasePanel> result = panelDBAdaptor.update(diseasePanelId, parameters); auditManager.recordUpdate(AuditRecord.Resource.panel, diseasePanelId, userId, parameters, null, null); return result; } @Override public QueryResult<VariableSetSummary> getVariableSetSummary(long variableSetId, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = studyDBAdaptor.getStudyIdByVariableSetId(variableSetId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.VIEW_VARIABLE_SET); QueryResult<VariableSet> variableSet = studyDBAdaptor.getVariableSet(variableSetId, new QueryOptions()); if (variableSet.getNumResults() == 0) { logger.error("getVariableSetSummary: Could not find variable set id {}. {} results returned", variableSetId, variableSet.getNumResults()); throw new CatalogDBException("Variable set " + variableSetId + " not found."); } int dbTime = 0; VariableSetSummary variableSetSummary = new VariableSetSummary(variableSetId, variableSet.first().getName()); QueryResult<VariableSummary> annotationSummary = sampleDBAdaptor.getAnnotationSummary(variableSetId); dbTime += annotationSummary.getDbTime(); variableSetSummary.setSamples(annotationSummary.getResult()); annotationSummary = cohortDBAdaptor.getAnnotationSummary(variableSetId); dbTime += annotationSummary.getDbTime(); variableSetSummary.setCohorts(annotationSummary.getResult()); annotationSummary = individualDBAdaptor.getAnnotationSummary(variableSetId); dbTime += annotationSummary.getDbTime(); variableSetSummary.setIndividuals(annotationSummary.getResult()); return new QueryResult<>("Variable set summary", dbTime, 1, 1, "", "", Arrays.asList(variableSetSummary)); } /* * Variables Methods */ @Override public QueryResult<VariableSet> createVariableSet(long studyId, String name, Boolean unique, String description, Map<String, Object> attributes, List<Variable> variables, String sessionId) throws CatalogException { ParamUtils.checkObj(variables, "Variables List"); Set<Variable> variablesSet = new HashSet<>(variables); if (variables.size() != variablesSet.size()) { throw new CatalogException("Error. Repeated variables"); } return createVariableSet(studyId, name, unique, description, attributes, variablesSet, sessionId); } @Override public QueryResult<VariableSet> createVariableSet(long studyId, String name, Boolean unique, String description, Map<String, Object> attributes, Set<Variable> variables, String sessionId) throws CatalogException { ParamUtils.checkParameter(name, "name"); ParamUtils.checkObj(variables, "Variables Set"); String userId = catalogManager.getUserManager().getId(sessionId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.WRITE_VARIABLE_SET); unique = ParamUtils.defaultObject(unique, true); description = ParamUtils.defaultString(description, ""); attributes = ParamUtils.defaultObject(attributes, new HashMap<String, Object>()); for (Variable variable : variables) { ParamUtils.checkParameter(variable.getName(), "variable ID"); ParamUtils.checkObj(variable.getType(), "variable Type"); variable.setAllowedValues(ParamUtils.defaultObject(variable.getAllowedValues(), Collections.<String>emptyList())); variable.setAttributes(ParamUtils.defaultObject(variable.getAttributes(), Collections.<String, Object>emptyMap())); variable.setCategory(ParamUtils.defaultString(variable.getCategory(), "")); variable.setDependsOn(ParamUtils.defaultString(variable.getDependsOn(), "")); variable.setDescription(ParamUtils.defaultString(variable.getDescription(), "")); // variable.setRank(defaultString(variable.getDescription(), "")); } VariableSet variableSet = new VariableSet(-1, name, unique, description, variables, attributes); CatalogAnnotationsValidator.checkVariableSet(variableSet); QueryResult<VariableSet> queryResult = studyDBAdaptor.createVariableSet(studyId, variableSet); // auditManager.recordCreation(AuditRecord.Resource.variableSet, queryResult.first().getId(), userId, queryResult.first(), null, null); auditManager.recordAction(AuditRecord.Resource.variableSet, AuditRecord.Action.create, AuditRecord.Magnitude.low, queryResult.first().getId(), userId, null, queryResult.first(), null, null); return queryResult; } @Override public QueryResult<VariableSet> readVariableSet(long variableSet, QueryOptions options, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = studyDBAdaptor.getStudyIdByVariableSetId(variableSet); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.VIEW_VARIABLE_SET); return studyDBAdaptor.getVariableSet(variableSet, options); } @Override public QueryResult<VariableSet> searchVariableSets(String studyStr, Query query, QueryOptions options, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = getId(userId, studyStr); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.VIEW_VARIABLE_SET); options = ParamUtils.defaultObject(options, QueryOptions::new); query = ParamUtils.defaultObject(query, Query::new); query.put(StudyDBAdaptor.VariableSetParams.STUDY_ID.key(), studyId); return studyDBAdaptor.getVariableSets(query, options); } @Override public QueryResult<VariableSet> deleteVariableSet(long variableSetId, QueryOptions queryOptions, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = studyDBAdaptor.getStudyIdByVariableSetId(variableSetId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.DELETE_VARIABLE_SET); QueryResult<VariableSet> queryResult = studyDBAdaptor.deleteVariableSet(variableSetId, queryOptions); auditManager.recordDeletion(AuditRecord.Resource.variableSet, variableSetId, userId, queryResult.first(), null, null); return queryResult; } @Override public QueryResult<VariableSet> addFieldToVariableSet(long variableSetId, Variable variable, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = studyDBAdaptor.getStudyIdByVariableSetId(variableSetId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.WRITE_VARIABLE_SET); QueryResult<VariableSet> queryResult = studyDBAdaptor.addFieldToVariableSet(variableSetId, variable); auditManager.recordDeletion(AuditRecord.Resource.variableSet, variableSetId, userId, queryResult.first(), null, null); return queryResult; } @Override public QueryResult<VariableSet> removeFieldFromVariableSet(long variableSetId, String name, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = studyDBAdaptor.getStudyIdByVariableSetId(variableSetId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.WRITE_VARIABLE_SET); QueryResult<VariableSet> queryResult = studyDBAdaptor.removeFieldFromVariableSet(variableSetId, name); auditManager.recordDeletion(AuditRecord.Resource.variableSet, variableSetId, userId, queryResult.first(), null, null); return queryResult; } @Override public QueryResult<VariableSet> renameFieldFromVariableSet(long variableSetId, String oldName, String newName, String sessionId) throws CatalogException { String userId = catalogManager.getUserManager().getId(sessionId); long studyId = studyDBAdaptor.getStudyIdByVariableSetId(variableSetId); authorizationManager.checkStudyPermission(studyId, userId, StudyAclEntry.StudyPermissions.WRITE_VARIABLE_SET); QueryResult<VariableSet> queryResult = studyDBAdaptor.renameFieldVariableSet(variableSetId, oldName, newName); auditManager.recordDeletion(AuditRecord.Resource.variableSet, variableSetId, userId, queryResult.first(), null, null); return queryResult; } }