def create_project(request): """Create a new project. HTTP POST Request body - should contain json params: name: Project name description: Project description Response body - will be json with the following structure, representing the created project: { 'projectsByGuid': { <projectGuid1> : { ... <project key-value pairs> ... } } } """ request_json = json.loads(request.body) if 'form' not in request_json: return create_json_response( {}, status=400, reason="Invalid request: 'form' not in request_json") form_data = request_json['form'] name = form_data.get('name') if not name: return create_json_response({}, status=400, reason="'Name' cannot be blank") description = form_data.get('description') project = Project.objects.create(created_by=request.user, name=name, description=description) # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished try: base_project, created = BaseProject.objects.get_or_create( project_id=_slugify(name)) if created: print("Created project %s" % base_project) base_project.project_name = name base_project.description = description base_project.save() project.deprecated_project_id = base_project.project_id project.save() except: raise projects_by_guid = { project.guid: _get_json_for_project(project, request.user) } return create_json_response({ 'projectsByGuid': projects_by_guid, })
def login_required_error(request): """Returns an HttpResponse with a 401 UNAUTHORIZED error message. This is used to redirect AJAX HTTP handlers to the login page. """ assert not request.user.is_authenticated() return create_json_response({}, status=401, reason="login required")
def case_review_page_data(request, project_guid): """Returns a JSON object containing information used by the case review page: :: json_response = { 'user': {..}, 'project': {..}, 'familiesByGuid': {..}, 'individualsByGuid': {..}, 'familyGuidToIndivGuids': {..}, } Args: project_guid (string): GUID of the project being case-reviewed. """ # get all families in this project project = Project.objects.filter(guid=project_guid) if not project: raise ValueError("Invalid project id: %s" % project_guid) project = project[0] json_response = { 'user': _get_json_for_user(request.user), 'project': _get_json_for_project(project, request.user), 'familiesByGuid': {}, 'individualsByGuid': {}, 'familyGuidToIndivGuids': {}, } for i in Individual.objects.filter(family__project=project).select_related('family'): # filter out individuals that were never in case review (or where case review status is set to -- ) if not i.case_review_status: continue # process family record if it hasn't been added already family = i.family if str(family.guid) not in json_response['familiesByGuid']: json_response['familiesByGuid'][family.guid] = _get_json_for_family(family) json_response['familyGuidToIndivGuids'][family.guid] = [] json_response['familyGuidToIndivGuids'][family.guid].append(i.guid) json_response['individualsByGuid'][i.guid] = _get_json_for_individual(i) return create_json_response(json_response)
def awesomebar_autocomplete(request): """Accepts HTTP GET request with q=.. url arg, and returns suggestions""" query = request.GET.get('q', None) results = {} if len(query) > 0: projects = _get_matching_projects(request.user, query) if projects: results['projects'] = {'name': 'Projects', 'results': projects} families = _get_matching_families(request.user, query) if families: results['families'] = {'name': 'Families', 'results': families} genes = _get_matching_genes(request.user, query) if genes: results['genes'] = {'name': 'Genes', 'results': genes} #from pprint import pprint #pprint(results) return create_json_response({'matches': results})
def delete_project(request, project_guid): """Update project metadata - including one or more of these fields: name, description Args: project_guid (string): GUID of the project that should be updated HTTP POST Response body - will be json with the delete projectGuid mapped to the special 'DELETE' keyword: { 'projectsByGuid': { <projectGuid1> : 'DELETE' } } """ project = Project.objects.get(guid=project_guid) # check permissions if not request.user.has_perm(IS_OWNER, project) and not request.user.is_staff: raise PermissionDenied project.delete() # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished try: base_project = BaseProject.objects.filter( project_id=project.deprecated_project_id) if base_project: base_project = base_project[0] base_project.delete() except: raise # TODO delete Family, Individual, and other objects under this project return create_json_response({ 'projectsByGuid': { project.guid: 'DELETE' }, })
def save_internal_case_review_summary(request, project_guid, family_guid): """Updates the `internal_case_review_summary` field for the given family. Args: project_guid (string): GUID of the project. family_guid (string): GUID of the family. """ family = Family.objects.get(guid=family_guid) requestJSON = json.loads(request.body) family.internal_case_review_brief_summary = requestJSON['form'] family.save() # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished try: base_f = BaseFamily.objects.get(project__project_id=family.project.deprecated_project_id, family_id=family.family_id) base_f.internal_case_review_brief_summary = requestJSON['form'] base_f.save() except: raise return create_json_response({family.guid: _get_json_for_family(family)})
def save_case_review_status(request, project_guid): """Updates the `case_review_status`, with initial case_review_page_data json embedded. Args: project_guid (string): GUID of the Project under case review. """ project = Project.objects.get(guid=project_guid) # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished base_project = BaseProject.objects.filter(project_id=project.deprecated_project_id) if base_project: base_project = base_project[0] requestJSON = json.loads(request.body) responseJSON = {} for individual_guid, new_case_review_status in requestJSON['form'].items(): i = Individual.objects.get(family__project=project, guid=individual_guid) if i.case_review_status == new_case_review_status: continue i.case_review_status = new_case_review_status i.case_review_status_last_modified_by = request.user i.case_review_status_last_modified_date = timezone.now() i.save() responseJSON[i.guid] = _get_json_for_individual(i) # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished try: if base_project: base_i = BaseIndividual.objects.get(family__project=base_project, indiv_id=i.individual_id) base_i.case_review_status = new_case_review_status base_i.save() except: raise return create_json_response(responseJSON)
def update_project(request, project_guid): """Update project metadata - including one or more of these fields: name, description Args: project_guid (string): GUID of the project that should be updated HTTP POST Request body - should contain one or more json params: name: Project name description: Project description Response body - will be json with the following structure, representing the updated project: { 'projectsByGuid': { <projectGuid1> : { ... <project key-value pairs> ... } } } """ project = Project.objects.get(guid=project_guid) # check permissions if not request.user.has_perm(CAN_EDIT, project) and not request.user.is_staff: raise PermissionDenied request_json = json.loads(request.body) if 'form' not in request_json: return create_json_response( {}, status=400, reason="Invalid request: 'form' not in request_json") form_data = request_json['form'] if 'name' in form_data: project.name = form_data.get('name') project.save() elif 'description' in form_data: project.description = form_data.get('description') project.save() # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished try: base_project = BaseProject.objects.filter( project_id=project.deprecated_project_id) if base_project: base_project = base_project[0] if 'name' in form_data: base_project.project_name = form_data.get('name') base_project.save() elif 'description' in form_data: base_project.description = form_data.get('description') base_project.save() except: raise projects_by_guid = { project.guid: _get_json_for_project(project, request.user) } return create_json_response({ 'projectsByGuid': projects_by_guid, })
def update_project_categories(request, project_guid): """Update ProjectCategories for the given project. Args: project_guid (string): GUID of the project that should be updated HTTP POST Request body - should contain one or more json params: categories: a list of category GUIDs for the categories assigned to the given project Response body - will be json with the following structure, representing the updated project, as well all categories in seqr: { 'projectsByGuid': { <projectGuid1> : { ... <project key-value pairs> ... } } 'projectCategoriesByGuid': { <projectCategoryGuid1> : { ... <category key-value pairs> ... } <projectCategoryGuid2> : { ... <category key-value pairs> ... } } } """ project = Project.objects.get(guid=project_guid) # check permissions if not request.user.has_perm(CAN_EDIT, project) and not request.user.is_staff: raise PermissionDenied request_json = json.loads(request.body) if 'form' not in request_json: return create_json_response( {}, status=400, reason="Invalid request: 'form' not in request_json") form_data = request_json['form'] # categories currently assigned to this project current_categories = set(form_data['categories']) # remove ProjectCategory mappings for categories the user wants to remove from this project project_categories_already_assigned = set() for project_category in project.projectcategory_set.all(): if project_category.guid not in current_categories: project_category.projects.remove(project) if project_category.projects.count() == 0: project_category.delete() else: # also record the project_category guids for which there's already a ProjectCategory # object mapped to this project and doesn't need to be added or removed project_categories_already_assigned.add(project_category.guid) # add mappings for ProjectCategory objects that are mapped to other projects, and that the user now wants to add to this project also project_categories_to_create = set(current_categories) for project_category in ProjectCategory.objects.filter( guid__in=current_categories): if project_category.guid not in project_categories_already_assigned: project_category.projects.add(project) project_categories_to_create.remove(project_category.guid) # create ProjectCategory objects for new categories, and add mappings for them to this project project_categories_by_guid = {} for category_name in project_categories_to_create: project_category = ProjectCategory.objects.create( name=category_name, created_by=request.user) project_category.projects.add(project) project_categories_by_guid[ project_category.guid] = project_category.json() projects_by_guid = { project.guid: _get_json_for_project(project, request.user) } return create_json_response({ 'projectsByGuid': projects_by_guid, 'projectCategoriesByGuid': project_categories_by_guid, })
def dashboard_page_data(request): """Returns a JSON object containing information used by the case review page: :: json_response = { 'user': {..}, 'familiesByGuid': {..}, 'individualsByGuid': {..}, 'familyGuidToIndivGuids': {..}, } Args: project_guid (string): GUID of the Project under case review. """ # get all projects this user has permissions to view if request.user.is_staff: projects = projects_user_can_edit = Project.objects.all() projects_WHERE_clause = '' else: projects = Project.objects.filter(can_view_group__user=request.user) projects_WHERE_clause = 'WHERE p.guid in (%s)' % (','.join( "'%s'" % p.guid for p in projects)) projects_user_can_edit = Project.objects.filter( can_edit_group__user=request.user) # use raw SQL to avoid making N+1 queries. num_families_subquery = """ SELECT count(*) FROM seqr_family WHERE project_id=p.id """.strip() num_variant_tags_subquery = """ SELECT count(*) FROM seqr_varianttag AS v JOIN seqr_varianttagtype AS t ON v.variant_tag_type_id=t.id WHERE project_id=p.id """.strip() num_individuals_subquery = """ SELECT count(*) FROM seqr_individual AS i JOIN seqr_family AS f ON i.family_id=f.id WHERE f.project_id=p.id """.strip() projects_query = """ SELECT guid AS project_guid, p.name AS name, description, deprecated_project_id, created_date, deprecated_last_accessed_date, (%(num_variant_tags_subquery)s) AS num_variant_tags, (%(num_families_subquery)s) AS num_families, (%(num_individuals_subquery)s) AS num_individuals FROM seqr_project AS p %(projects_WHERE_clause)s """.strip() % locals() cursor = connection.cursor() cursor.execute(projects_query) key_map = {'deprecated_last_accessed_date': 'last_accessed_date'} columns = [ _to_camel_case(_remap_key(col[0], key_map)) for col in cursor.description ] projects_by_guid = { r['projectGuid']: r for r in (dict(zip(columns, row)) for row in cursor.fetchall()) } # retrieve solve counts for each project ANALYSIS_STATUS_CATEGORIES = { 'S': 'Solved', 'S_kgfp': 'Solved', 'S_kgdp': 'solved', 'S_ng': 'Solved', 'Sc_kgfp': 'Strong candidate', 'Sc_kgdp': 'Strong candidate', 'Sc_ng': 'Strong candidate', 'Rncc': 'Reviewed, no candidate', 'Rcpc': 'Analysis in progress', 'I': 'Analysis in progress', 'Q': 'Waiting for data', } analysis_status_query = """ SELECT p.guid AS project_guid, f.analysis_status AS analysis_status, count(*) as analysis_status_count FROM seqr_family AS f JOIN seqr_project AS p ON f.project_id = p.id GROUP BY p.guid, f.analysis_status """.strip() % locals() cursor.execute(analysis_status_query) columns = [col[0] for col in cursor.description] for row in cursor.fetchall(): analysis_status_record = dict(zip(columns, row)) project_guid = analysis_status_record['project_guid'] analysis_status_count = analysis_status_record['analysis_status_count'] analysis_status_category = ANALYSIS_STATUS_CATEGORIES[ analysis_status_record['analysis_status']] if 'analysisStatusCounts' not in projects_by_guid[project_guid]: projects_by_guid[project_guid]['analysisStatusCounts'] = {} analysis_status_counts_dict = projects_by_guid[project_guid][ 'analysisStatusCounts'] analysis_status_counts_dict[ analysis_status_category] = analysis_status_counts_dict.get( analysis_status_category, 0) + analysis_status_count # retrieve all project categories for project_guid in projects_by_guid: projects_by_guid[project_guid]['projectCategoryGuids'] = [] project_categories_by_guid = {} for project_category in ProjectCategory.objects.all(): project_category_guid = project_category.guid for p in project_category.projects.all(): projects_by_guid[p.guid]['projectCategoryGuids'].append( project_category_guid) project_categories_by_guid[ project_category_guid] = project_category.json() # do a separate query to get details on all datasets in these projects num_samples_subquery = """ SELECT COUNT(*) FROM seqr_sequencingsample AS subquery_s WHERE subquery_s.dataset_id=d.id """ datasets_query = """ SELECT p.guid AS project_guid, d.guid AS dataset_guid, d.id AS dataset_id, d.sequencing_type AS sequencing_type, d.is_loaded AS is_loaded, (%(num_samples_subquery)s) AS num_samples FROM seqr_dataset AS d JOIN seqr_sequencingsample AS s ON d.id=s.dataset_id JOIN seqr_individual_sequencing_samples AS iss ON iss.sequencingsample_id=s.id JOIN seqr_individual AS i ON iss.individual_id=i.id JOIN seqr_family AS f ON i.family_id=f.id JOIN seqr_project AS p ON f.project_id=p.id %(projects_WHERE_clause)s GROUP BY p.guid, d.guid, d.id, d.sequencing_type, d.is_loaded """.strip() % locals() cursor.execute(datasets_query) columns = [_to_camel_case(col[0]) for col in cursor.description] datasets_by_guid = {} for row in cursor.fetchall(): dataset_project_record = dict(zip(columns, row)) project_guid = dataset_project_record['projectGuid'] dataset_guid = dataset_project_record['datasetGuid'] del dataset_project_record['projectGuid'] del dataset_project_record['datasetGuid'] project_record = projects_by_guid[project_guid] if 'datasets' not in project_record: project_record['datasetGuids'] = [] project_record['datasetGuids'].append(dataset_guid) datasets_by_guid[dataset_guid] = dataset_project_record cursor.close() # mark all projects where this user has edit permissions for project in projects_user_can_edit: projects_by_guid[project.guid]['canEdit'] = True json_response = { 'user': _get_json_for_user(request.user), 'projectsByGuid': projects_by_guid, 'projectCategoriesByGuid': project_categories_by_guid, 'datasetsByGuid': datasets_by_guid, } return create_json_response(json_response)