def phenotips_edit_handler(request, project_guid, patient_id): """Request the PhenoTips Edit page for the given patient_id, and forwards PhenoTips' response to the client. Args: request: Django HTTP request object project_guid (string): project GUID for the seqr project containing this individual patient_id (string): PhenoTips internal patient id """ # query string forwarding needed for PedigreeEditor button query_string = request.META["QUERY_STRING"] url = "/bin/edit/data/{patient_id}?{query_string}".format( patient_id=patient_id, query_string=query_string) project = Project.objects.get(guid=project_guid) check_permissions(project, request.user, CAN_EDIT) auth_tuple = _get_phenotips_username_and_password( request.user, project, permissions_level=CAN_EDIT) return proxy_request(request, url, headers={}, auth_tuple=auth_tuple, host=settings.PHENOTIPS_SERVER)
def _phenotips_view_handler(request, project_guid, individual_guid, url_template, permission_level=CAN_VIEW): """Requests the PhenoTips PDF for the given patient_id, and forwards PhenoTips' response to the client. Args: request: Django HTTP request object project_guid (string): project GUID for the seqr project containing this individual individual_guid (string): individual GUID for the seqr individual corresponding to the desired patient """ project = Project.objects.get(guid=project_guid) check_permissions(project, request.user, CAN_VIEW) individual = Individual.objects.get(guid=individual_guid) _create_patient_if_missing(project, individual) _set_phenotips_patient_id_if_missing(project, individual) # query string forwarding needed for PedigreeEditor button query_string = request.META["QUERY_STRING"] url = url_template.format(patient_id=individual.phenotips_patient_id, query_string=query_string) auth_tuple = _get_phenotips_username_and_password( request.user, project, permissions_level=permission_level) return proxy_request(request, url, headers={}, auth_tuple=auth_tuple, host=settings.PHENOTIPS_SERVER)
def update_family_pedigree_image(request, family_guid): """Updates the specified field in the Family model. Args: family_guid (string): GUID of the family. """ family = Family.objects.get(guid=family_guid) # check permission check_permissions(family.project, request.user, CAN_EDIT) if len(request.FILES) == 0: pedigree_image = None elif len(request.FILES) > 1: return create_json_response({}, status=400, reason='Received {} files'.format( len(request.FILES))) else: pedigree_image = request.FILES.values()[0] update_seqr_model(family, pedigree_image=pedigree_image) return create_json_response( {family.guid: _get_json_for_family(family, request.user)})
def delete_mme_submission(request, individual_guid): """ Create or update the submission for the given individual. """ individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user) if individual.mme_deleted_date: return create_json_response( {}, status=402, reason='Matchmaker submission has already been deleted for {}'.format(individual.individual_id), ) matchbox_id = individual.mme_submitted_data['patient']['id'] response = requests.delete(url=MME_DELETE_INDIVIDUAL_URL, headers=MME_HEADERS, data=json.dumps({'id': matchbox_id})) if response.status_code != 200: try: response_json = response.json() except Exception: response_json = {} return create_json_response(response_json, status=response.status_code, reason=response.content) deleted_date = datetime.now() individual.mme_deleted_date = deleted_date individual.mme_deleted_by = request.user individual.save() return create_json_response({'individualsByGuid': {individual_guid: {'mmeDeletedDate': deleted_date}}})
def create_saved_variant_handler(request): variant_json = json.loads(request.body) family_guid = variant_json.pop('familyGuid') non_variant_json = { k: variant_json.pop(k, None) for k in ['searchHash', 'tags', 'functionalData', 'notes', 'note', 'submitToClinvar'] } family = Family.objects.get(guid=family_guid) check_permissions(family.project, request.user, CAN_VIEW) xpos = variant_json['xpos'] ref = variant_json['ref'] alt = variant_json['alt'] # TODO remove project field from saved variants saved_variant = SavedVariant.objects.create( xpos=xpos, xpos_start=xpos, xpos_end=xpos + len(ref) - 1, ref=ref, alt=alt, family=family, project=family.project, saved_variant_json=json.dumps(variant_json) ) if non_variant_json.get('note'): _create_variant_note(saved_variant, non_variant_json, request.user) elif non_variant_json.get('tags'): _create_new_tags(saved_variant, non_variant_json, request.user) variant_json.update(get_json_for_saved_variant(saved_variant, add_tags=True, project_guid=family.project.guid)) return create_json_response({ 'savedVariantsByGuid': {saved_variant.guid: variant_json}, })
def delete_mme_submission(request, individual_guid): """ Create or update the submission for the given individual. """ individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user) if individual.mme_deleted_date: return create_json_response( {}, status=402, reason='Matchmaker submission has already been deleted for {}'.format(individual.individual_id), ) matchbox_id = individual.mme_submitted_data['patient']['id'] response = requests.delete(url=MME_DELETE_INDIVIDUAL_URL, headers=MME_HEADERS, data=json.dumps({'id': matchbox_id})) if response.status_code != 200: try: response_json = response.json() except Exception: response_json = {} return create_json_response(response_json, status=response.status_code, reason=response.content) deleted_date = datetime.now() individual.mme_deleted_date = deleted_date individual.mme_deleted_by = request.user individual.save() for saved_result in MatchmakerResult.objects.filter(individual=individual): if not (saved_result.we_contacted or saved_result.host_contacted or saved_result.comments): saved_result.delete() return create_json_response({'individualsByGuid': {individual_guid: {'mmeDeletedDate': deleted_date}}})
def get_individual_mme_matches(request, individual_guid): """ Looks for matches for the given individual. Expects a single patient (MME spec) in the POST data field under key "patient_data" Args: project_id,indiv_id and POST all data in POST under key "patient_data" Returns: Status code and results """ individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user) results = MatchmakerResult.objects.filter(individual=individual) saved_variants = get_json_for_saved_variants( SavedVariant.objects.filter(family=individual.family), add_tags=True, add_details=True, project=project, user=request.user) gene_ids = set() for variant in saved_variants: gene_ids.update(variant['transcripts'].keys()) return _parse_mme_results( individual, results, request.user, additional_genes=gene_ids, response_json={ 'savedVariantsByGuid': {variant['variantGuid']: variant for variant in saved_variants}})
def update_individual_handler(request, individual_guid): """Updates a single field in an Individual record. Args: request (object): Django HTTP Request object. individual_guid (string): GUID of the Individual. Request: body should be a json dictionary like: { 'value': xxx } Response: json dictionary representing the updated individual like: { <individualGuid> : { individualId: xxx, sex: xxx, affected: xxx, ... } } """ individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user, CAN_EDIT) request_json = json.loads(request.body) update_individual_from_json(individual, request_json, user=request.user, allow_unknown_keys=True) return create_json_response({ individual.guid: _get_json_for_individual(individual, request.user) })
def update_family_assigned_analyst(request, family_guid): """Updates the specified field in the Family model. Args: family_guid (string): GUID of the family. """ family = Family.objects.get(guid=family_guid) check_permissions(family.project, request.user, CAN_EDIT) request_json = json.loads(request.body) assigned_analyst_username = request_json.get('assigned_analyst_username') if assigned_analyst_username: try: assigned_analyst = User.objects.get( username=assigned_analyst_username) except Exception: return create_json_response({}, status=400, reason="specified user does not exist") else: assigned_analyst = None update_seqr_model(family, assigned_analyst=assigned_analyst) return create_json_response( {family.guid: _get_json_for_family(family, request.user)})
def update_individual_hpo_terms(request, individual_guid): individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user, CAN_EDIT) features = json.loads(request.body) _create_patient_if_missing(project, individual) patient_json = _get_patient_data(project, individual) patient_json["features"] = features patient_json_string = json.dumps(patient_json) url = _phenotips_patient_url(individual) auth_tuple = _get_phenotips_uname_and_pwd_for_project(project.phenotips_user_id, read_only=False) _make_api_call('PUT', url, data=patient_json_string, auth_tuple=auth_tuple, expected_status_code=204) phenotips_patient_id = patient_json['id'] phenotips_eid = patient_json.get('external_id') update_seqr_model( individual, phenotips_data=json.dumps(patient_json), phenotips_patient_id=phenotips_patient_id, phenotips_eid=phenotips_eid) return create_json_response({ individual.guid: { 'phenotipsData': patient_json, 'phenotipsPatientId': phenotips_patient_id, 'phenotipsEid': phenotips_eid } })
def update_family_field_handler(request, family_guid, field_name): """Updates the specified field in the Family model. Args: family_guid (string): GUID of the family. field_name (string): Family model field name to update """ family = Family.objects.get(guid=family_guid) # check permission project = family.project check_permissions(project, request.user, CAN_EDIT) request_json = json.loads(request.body) if "value" not in request_json: raise ValueError("Request is missing 'value' key: %s" % (request.body, )) value = request_json['value'] family_json = {field_name: value} update_family_from_json(family, family_json) _deprecated_update_original_family_field(project, family, field_name, value) return create_json_response( {family.guid: _get_json_for_family(family, request.user)})
def update_variant_tags_handler(request, variant_guids): request_json = json.loads(request.body) family_guid = request_json.pop('familyGuid') family = Family.objects.get(guid=family_guid) check_permissions(family.project, request.user, CAN_VIEW) all_variant_guids = set(variant_guids.split(',')) saved_variants = SavedVariant.objects.filter(guid__in=all_variant_guids) if len(saved_variants) != len(all_variant_guids): error = 'Unable to find the following variant(s): {}'.format( ', '.join([guid for guid in all_variant_guids if guid not in {sv.guid for sv in saved_variants}])) return create_json_response({'error': error}, status=400, reason=error) deleted_tag_guids = _delete_removed_tags(saved_variants, all_variant_guids, request_json.get('tags', [])) created_tags = _create_new_tags(saved_variants, request_json, request.user) tag_updates = {tag['tagGuid']: tag for tag in get_json_for_variant_tags(created_tags)} tag_updates.update({guid: None for guid in deleted_tag_guids}) return create_json_response({ 'savedVariantsByGuid': {saved_variant.guid: { 'tagGuids': [t.guid for t in saved_variant.varianttag_set.all()], } for saved_variant in saved_variants}, 'variantTagsByGuid': tag_updates, })
def create_saved_variant_handler(request): variant_json = json.loads(request.body) family_guid = variant_json['familyGuid'] family = Family.objects.get(guid=family_guid) check_permissions(family.project, request.user, CAN_VIEW) if isinstance(variant_json['variant'], list): # are compound hets saved_variants = [] for single_variant_json in variant_json['variant']: saved_variant, created = SavedVariant.objects.get_or_create( **_get_parsed_variant_args(single_variant_json, family)) if created: saved_variant.saved_variant_json = single_variant_json saved_variant.save() saved_variants.append(saved_variant) else: saved_variant = SavedVariant.objects.create( saved_variant_json=variant_json['variant'], **_get_parsed_variant_args(variant_json['variant'], family)) saved_variants = [saved_variant] if variant_json.get('note'): _create_variant_note(saved_variants, variant_json, request.user) elif variant_json.get('tags'): _create_new_tags(saved_variants, variant_json, request.user) return create_json_response( get_json_for_saved_variants_with_tags(saved_variants, add_details=True))
def delete_variant_note_handler(request, variant_guids, note_guid): variant_guids = variant_guids.split(',') note = VariantNote.objects.get(guid=note_guid) projects = { saved_variant.family.project for saved_variant in note.saved_variants.all() } for project in projects: check_permissions(project, request.user, CAN_VIEW) note.delete() saved_variants_by_guid = {} for saved_variant in SavedVariant.objects.filter(guid__in=variant_guids): notes = saved_variant.variantnote_set.all() saved_variants_by_guid[saved_variant.guid] = { 'noteGuids': [n.guid for n in notes] } if not notes: if not saved_variant.varianttag_set.count() > 0: saved_variant.delete() saved_variants_by_guid[saved_variant.guid] = None return create_json_response({ 'savedVariantsByGuid': saved_variants_by_guid, 'variantNotesByGuid': { note_guid: None }, })
def update_variant_tags_handler(request, variant_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_EDIT) request_json = json.loads(request.body) updated_tags = request_json.get('tags', []) updated_functional_data = request_json.get('functionalData', []) # Update tags existing_tag_guids = [tag['tagGuid'] for tag in updated_tags if tag.get('tagGuid')] new_tags = [tag for tag in updated_tags if not tag.get('tagGuid')] for tag in saved_variant.varianttag_set.exclude(guid__in=existing_tag_guids): delete_seqr_model(tag) for tag in new_tags: variant_tag_type = VariantTagType.objects.get( Q(name=tag['name']), Q(project=saved_variant.project) | Q(project__isnull=True) ) create_seqr_model( VariantTag, saved_variant=saved_variant, variant_tag_type=variant_tag_type, search_parameters=request_json.get('searchParameters'), created_by=request.user, ) # Update functional data existing_functional_guids = [tag['tagGuid'] for tag in updated_functional_data if tag.get('tagGuid')] for tag in saved_variant.variantfunctionaldata_set.exclude(guid__in=existing_functional_guids): delete_seqr_model(tag) for tag in updated_functional_data: if tag.get('tagGuid'): tag_model = VariantFunctionalData.objects.get( guid=tag.get('tagGuid'), functional_data_tag=tag.get('name'), saved_variant=saved_variant ) update_model_from_json(tag_model, tag, allow_unknown_keys=True) else: create_seqr_model( VariantFunctionalData, saved_variant=saved_variant, functional_data_tag=tag.get('name'), metadata=tag.get('metadata'), search_parameters=request_json.get('searchParameters'), created_by=request.user, ) return create_json_response({ variant_guid: { 'tags': [get_json_for_variant_tag(tag) for tag in saved_variant.varianttag_set.all()], 'functionalData': [get_json_for_variant_functional_data(tag) for tag in saved_variant.variantfunctionaldata_set.all()] } })
def phenotips_edit_handler(request, project_guid, patient_id): """Request the PhenoTips Edit page for the given patient_id, and forwards PhenoTips' response to the client. Args: request: Django HTTP request object project_guid (string): project GUID for the seqr project containing this individual patient_id (string): PhenoTips internal patient id """ # query string forwarding needed for PedigreeEditor button query_string = request.META["QUERY_STRING"] url = "/bin/edit/data/%(patient_id)s?%(query_string)s" % locals() project = Project.objects.get(guid=project_guid) check_permissions(project, request.user, CAN_EDIT) auth_tuple = _get_phenotips_username_and_password(request.user, project, permissions_level=CAN_EDIT) #if 'current_phenotips_session' not in request.session: # phenotips_session = requests.Session() # request.session['current_phenotips_session'] = pickle.dumps(phenotips_session) #else: # phenotips_session = pickle.loads(request.session['current_phenotips_session']) return _send_request_to_phenotips('GET', url, scheme=request.scheme, auth_tuple=auth_tuple) #, session=phenotips_session)
def update_individual_hpo_terms(request, individual_guid): individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user, CAN_EDIT) features = json.loads(request.body) _create_patient_if_missing(project, individual) patient_json = _get_patient_data(project, individual) patient_json["features"] = features patient_json_string = json.dumps(patient_json) url = phenotips_patient_url(individual) auth_tuple = get_phenotips_uname_and_pwd_for_project(project.phenotips_user_id, read_only=False) make_phenotips_api_call('PUT', url, data=patient_json_string, auth_tuple=auth_tuple, expected_status_code=204) phenotips_patient_id = patient_json['id'] phenotips_eid = patient_json.get('external_id') individual.phenotips_data = json.dumps(patient_json) individual.phenotips_patient_id = phenotips_patient_id individual.phenotips_eid = phenotips_eid individual.save() return create_json_response({ individual.guid: { 'phenotipsData': patient_json, 'phenotipsPatientId': phenotips_patient_id, 'phenotipsEid': phenotips_eid } })
def _get_project_details(project, user): check_permissions(project, user) project_json = _get_json_for_project(project, user) families_by_guid, individuals_by_guid, samples_by_guid, analysis_groups_by_guid, locus_lists_by_guid = get_project_child_entities( project, user) project_json.update({ 'hasGeneSearch': True, 'locusListGuids': locus_lists_by_guid.keys(), 'variantTagTypes': get_project_variant_tag_types(project), 'variantFunctionalTagTypes': get_json_for_variant_functional_data_tag_types(), }) return { 'projectsByGuid': { project.guid: project_json }, 'familiesByGuid': families_by_guid, 'individualsByGuid': individuals_by_guid, 'samplesByGuid': samples_by_guid, 'locusListsByGuid': locus_lists_by_guid, 'analysisGroupsByGuid': analysis_groups_by_guid, }
def create_variant_note_handler(request, variant_guids): request_json = json.loads(request.body) save_as_gene_note = request_json.get('saveAsGeneNote') family_guid = request_json.pop('familyGuid') family = Family.objects.get(guid=family_guid) check_permissions(family.project, request.user, CAN_VIEW) all_variant_guids = variant_guids.split(',') saved_variants = SavedVariant.objects.filter(guid__in=all_variant_guids) if len(saved_variants) != len(all_variant_guids): error = 'Unable to find the following variant(s): {}'.format(', '.join( [ guid for guid in all_variant_guids if guid not in {sv.guid for sv in saved_variants} ])) return create_json_response({'error': error}, status=400, reason=error) # update saved_variants note = _create_variant_note(saved_variants, request_json, request.user) note_json = get_json_for_variant_note(note, add_variant_guids=False) note_json['variantGuids'] = all_variant_guids response = { 'savedVariantsByGuid': { saved_variant.guid: { 'noteGuids': [n.guid for n in saved_variant.variantnote_set.all()] } for saved_variant in saved_variants }, 'variantNotesByGuid': { note.guid: note_json }, } if save_as_gene_note: main_transcript_id = saved_variants[ 0].selected_main_transcript_id or saved_variants[ 0].saved_variant_json['mainTranscriptId'] gene_id = next( (gene_id for gene_id, transcripts in saved_variants[0]. saved_variant_json['transcripts'].items() if any( t['transcriptId'] == main_transcript_id for t in transcripts)), None) if main_transcript_id else None GeneNote.objects.create( note=request_json.get('note'), gene_id=gene_id, created_by=request.user, ) response['genesById'] = { gene_id: { 'notes': get_json_for_gene_notes_by_gene_id([gene_id], request.user)[gene_id], } } return create_json_response(response)
def update_variant_main_transcript(request, variant_guid, transcript_id): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.family.project, request.user, CAN_EDIT) saved_variant.selected_main_transcript_id = transcript_id saved_variant.save() return create_json_response({'savedVariantsByGuid': {variant_guid: {'selectedMainTranscriptId': transcript_id}}})
def delete_variant_note_handler(request, variant_guid, note_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_EDIT) note = VariantNote.objects.get(guid=note_guid, saved_variant=saved_variant) delete_seqr_model(note) return create_json_response({variant_guid: { 'notes': [get_json_for_variant_note(tag) for tag in saved_variant.variantnote_set.all()] }})
def delete_variant_note_handler(request, variant_guid, note_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_VIEW) note = VariantNote.objects.get(guid=note_guid, saved_variant=saved_variant) delete_seqr_model(note) return create_json_response({'savedVariantsByGuid': {variant_guid: { 'notes': [get_json_for_variant_note(tag) for tag in saved_variant.variantnote_set.all()] }}})
def create_variant_note_handler(request, variant_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_VIEW) _create_variant_note(saved_variant, json.loads(request.body), request.user) return create_json_response({'savedVariantsByGuid': {variant_guid: { 'notes': [get_json_for_variant_note(tag) for tag in saved_variant.variantnote_set.all()] }}})
def update_project_categories_handler(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 the following json structure: { 'form' : { 'categories': a list of category GUIDs for the categories assigned to the given project } } Response body - will contain 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 check_permissions(project, request.user, CAN_EDIT) 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'] # project categories according to the UI current_category_guids = set(form_data['categories']) project_categories_by_guid = _update_project_categories( project, request.user, current_category_guids) 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 update_variant_tags_handler(request, variant_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.family.project, request.user, CAN_VIEW) request_json = json.loads(request.body) updated_tags = request_json.get('tags', []) updated_functional_data = request_json.get('functionalData', []) # Update tags existing_tag_guids = [ tag['tagGuid'] for tag in updated_tags if tag.get('tagGuid') ] saved_variant.varianttag_set.exclude(guid__in=existing_tag_guids).delete() _create_new_tags(saved_variant, request_json, request.user) # Update functional data existing_functional_guids = [ tag['tagGuid'] for tag in updated_functional_data if tag.get('tagGuid') ] saved_variant.variantfunctionaldata_set.exclude( guid__in=existing_functional_guids).delete() for tag in updated_functional_data: if tag.get('tagGuid'): tag_model = VariantFunctionalData.objects.get( guid=tag.get('tagGuid'), functional_data_tag=tag.get('name'), saved_variant=saved_variant) update_model_from_json(tag_model, tag, allow_unknown_keys=True) else: VariantFunctionalData.objects.create( saved_variant=saved_variant, functional_data_tag=tag.get('name'), metadata=tag.get('metadata'), search_hash=request_json.get('searchHash'), created_by=request.user, ) return create_json_response({ 'savedVariantsByGuid': { variant_guid: { 'tags': [ get_json_for_variant_tag(tag) for tag in saved_variant.varianttag_set.all() ], 'functionalData': [ get_json_for_variant_functional_data(tag) for tag in saved_variant.variantfunctionaldata_set.all() ] } } })
def update_mme_submission(request, individual_guid): """ Create or update the submission for the given individual. """ individual = Individual.objects.get(guid=individual_guid) check_permissions(individual.family.project, request.user) submission_json = json.loads(request.body) submission_json.pop('individualGuid', {}) phenotypes = submission_json.pop('phenotypes', []) gene_variants = submission_json.pop('geneVariants', []) if not phenotypes and not gene_variants: return create_json_response({}, status=400, reason='Genotypes or phentoypes are required') if not submission_json.get('patient', {}).get('id'): return create_json_response({}, status=400, reason='Patient id is required') genomic_features = [] for gene_variant in gene_variants: if not gene_variant.get('geneId'): return create_json_response({}, status=400, reason='Gene id is required for genomic features') feature = {'gene': {'id': gene_variant['geneId']}} if 'numAlt' in gene_variant: feature['zygosity'] = gene_variant['numAlt'] % 2 if gene_variant.get('pos'): feature['variant'] = { 'alternateBases': gene_variant['alt'], 'referenceBases': gene_variant['ref'], 'referenceName': gene_variant['chrom'], 'start': gene_variant['pos'], 'assembly': GENOME_VERSION_LOOKUP[gene_variant['genomeVersion']], } genomic_features.append(feature) submission_json['patient']['genomicFeatures'] = genomic_features submission_json['patient']['features'] = phenotypes response = requests.post(url=MME_ADD_INDIVIDUAL_URL, headers=MME_HEADERS, data=json.dumps(submission_json)) if response.status_code not in (200, 409): try: response_json = response.json() except Exception: response_json = {} return create_json_response(response_json, status=response.status_code, reason=response.content) submitted_date = datetime.now() individual.mme_submitted_data = submission_json individual.mme_submitted_date = submitted_date individual.mme_deleted_date = None individual.mme_deleted_by = None individual.save() # search for new matches return _search_individual_matches(individual, request.user)
def update_variant_note_handler(request, variant_guid, note_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_VIEW) note = VariantNote.objects.get(guid=note_guid, saved_variant=saved_variant) request_json = json.loads(request.body) update_model_from_json(note, request_json, allow_unknown_keys=True) return create_json_response({'savedVariantsByGuid': {variant_guid: { 'notes': [get_json_for_variant_note(tag) for tag in saved_variant.variantnote_set.all()] }}})
def update_variant_note_handler(request, variant_guid, note_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_EDIT) note = VariantNote.objects.get(guid=note_guid, saved_variant=saved_variant) request_json = json.loads(request.body) update_model_from_json(note, request_json, allow_unknown_keys=True) return create_json_response({variant_guid: { 'notes': [get_json_for_variant_note(tag) for tag in saved_variant.variantnote_set.all()] }})
def update_project_handler(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 the following json structure: { 'form' : { 'name': <project name>, 'description': <project description>, } } Response body - will contain the following structure, representing the updated project: { 'projectsByGuid': { <projectGuid1> : { ... <project key-value pairs> ... } } } """ project = Project.objects.get(guid=project_guid) check_permissions(project, request.user, CAN_EDIT) 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() if '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 _deprecated_update_original_project(project) return create_json_response({ 'projectsByGuid': { project.guid: _get_json_for_project(project, request.user) }, })
def search_individual_mme_matches(request, individual_guid): """ Looks for matches for the given individual. Expects a single patient (MME spec) in the POST data field under key "patient_data" Args: project_id,indiv_id and POST all data in POST under key "patient_data" Returns: Status code and results """ individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user) return _search_individual_matches(individual, request.user)
def update_variant_note_handler(request, variant_guids, note_guid): note = VariantNote.objects.get(guid=note_guid) projects = {saved_variant.family.project for saved_variant in note.saved_variants.all()} for project in projects: check_permissions(project, request.user, CAN_VIEW) request_json = json.loads(request.body) update_model_from_json(note, request_json, allow_unknown_keys=True) note_json = get_json_for_variant_note(note, add_variant_guids=False) note_json['variantGuids'] = variant_guids.split(',') return create_json_response({ 'variantNotesByGuid': {note.guid: note_json}, })
def update_family_analysed_by(request, family_guid): """Updates the specified field in the Family model. Args: family_guid (string): GUID of the family. field_name (string): Family model field name to update """ family = Family.objects.get(guid=family_guid) check_permissions(family.project, request.user, CAN_EDIT) create_seqr_model(FamilyAnalysedBy, family=family, created_by=request.user) return create_json_response( {family.guid: _get_json_for_family(family, request.user)})
def saved_variant_transcripts(request, variant_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_VIEW) # TODO when variant search is rewritten for seqr models use that here base_project = find_matching_xbrowse_model(saved_variant.project) loaded_variant = get_datastore(base_project).get_single_variant( base_project.project_id, saved_variant.family.family_id, saved_variant.xpos, saved_variant.ref, saved_variant.alt, ) return create_json_response({variant_guid: {'transcripts': _variant_transcripts(loaded_variant.annotation)}})
def delete_variant_note_handler(request, variant_guid, note_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.family.project, request.user, CAN_VIEW) VariantNote.objects.get(guid=note_guid, saved_variant=saved_variant).delete() return create_json_response({ 'savedVariantsByGuid': { variant_guid: { 'notes': [ get_json_for_variant_note(tag) for tag in saved_variant.variantnote_set.all() ] } } })
def delete_variant_note_handler(request, variant_guids, note_guid): variant_guids = variant_guids.split(',') note = VariantNote.objects.get(guid=note_guid) projects = {saved_variant.family.project for saved_variant in note.saved_variants.all()} for project in projects: check_permissions(project, request.user, CAN_VIEW) note.delete() return create_json_response({ 'savedVariantsByGuid': { saved_variant.guid: {'noteGuids': [n.guid for n in saved_variant.variantnote_set.all()]} for saved_variant in SavedVariant.objects.filter(guid__in=variant_guids) }, 'variantNotesByGuid': {note_guid: None}, })
def update_variant_tags_handler(request, variant_guid): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_permissions(saved_variant.project, request.user, CAN_VIEW) request_json = json.loads(request.body) updated_tags = request_json.get('tags', []) updated_functional_data = request_json.get('functionalData', []) # Update tags existing_tag_guids = [tag['tagGuid'] for tag in updated_tags if tag.get('tagGuid')] for tag in saved_variant.varianttag_set.exclude(guid__in=existing_tag_guids): delete_seqr_model(tag) _create_new_tags(saved_variant, request_json, request.user) # Update functional data existing_functional_guids = [tag['tagGuid'] for tag in updated_functional_data if tag.get('tagGuid')] for tag in saved_variant.variantfunctionaldata_set.exclude(guid__in=existing_functional_guids): delete_seqr_model(tag) for tag in updated_functional_data: if tag.get('tagGuid'): tag_model = VariantFunctionalData.objects.get( guid=tag.get('tagGuid'), functional_data_tag=tag.get('name'), saved_variant=saved_variant ) update_model_from_json(tag_model, tag, allow_unknown_keys=True) else: create_seqr_model( VariantFunctionalData, saved_variant=saved_variant, functional_data_tag=tag.get('name'), metadata=tag.get('metadata'), search_hash=request_json.get('searchHash'), created_by=request.user, ) return create_json_response({'savedVariantsByGuid': { variant_guid: { 'tags': [get_json_for_variant_tag(tag) for tag in saved_variant.varianttag_set.all()], 'functionalData': [get_json_for_variant_functional_data(tag) for tag in saved_variant.variantfunctionaldata_set.all()] } }})
def update_family_analysed_by(request, family_guid): """Updates the specified field in the Family model. Args: family_guid (string): GUID of the family. field_name (string): Family model field name to update """ family = Family.objects.get(guid=family_guid) # analysed_by can be edited by anyone with access to the project check_permissions(family.project, request.user, CAN_VIEW) FamilyAnalysedBy.objects.create(family=family, created_by=request.user) return create_json_response( {family.guid: _get_json_for_family(family, request.user)})
def update_family_analysed_by(request, family_guid): """Updates the specified field in the Family model. Args: family_guid (string): GUID of the family. field_name (string): Family model field name to update """ family = Family.objects.get(guid=family_guid) check_permissions(family.project, request.user, CAN_EDIT) create_seqr_model(FamilyAnalysedBy, family=family, created_by=request.user) return create_json_response({ family.guid: _get_json_for_family(family, request.user) })
def update_project_categories_handler(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 the following json structure: { 'form' : { 'categories': a list of category GUIDs for the categories assigned to the given project } } Response body - will contain 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 check_permissions(project, request.user, CAN_EDIT) request_json = json.loads(request.body) # project categories according to the UI current_category_guids = set(request_json['categories']) project_categories_by_guid = _update_project_categories(project, request.user, current_category_guids) 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 update_mme_result_status(request, matchmaker_result_guid): """ Looks for matches for the given individual. Expects a single patient (MME spec) in the POST data field under key "patient_data" Args: project_id,indiv_id and POST all data in POST under key "patient_data" Returns: Status code and results """ result = MatchmakerResult.objects.get(guid=matchmaker_result_guid) project = result.individual.family.project check_permissions(project, request.user) request_json = json.loads(request.body) update_model_from_json(result, request_json, allow_unknown_keys=True) return create_json_response({ 'mmeResultsByGuid': {matchmaker_result_guid: {'matchStatus': _get_json_for_model(result)}}, })
def update_family_fields_handler(request, family_guid): """Updates the specified field in the Family model. Args: family_guid (string): GUID of the family. """ family = Family.objects.get(guid=family_guid) # check permission project = family.project check_permissions(project, request.user, CAN_EDIT) request_json = json.loads(request.body) update_family_from_json(family, request_json, user=request.user, allow_unknown_keys=True) return create_json_response({ family.guid: _get_json_for_family(family, request.user) })
def _get_project_details(project, user): check_permissions(project, user) project_json = _get_json_for_project(project, user) families_by_guid, individuals_by_guid, samples_by_guid, analysis_groups_by_guid, locus_lists_by_guid = get_project_child_entities(project, user) project_json.update({ 'hasGeneSearch': True, 'locusListGuids': locus_lists_by_guid.keys(), 'variantTagTypes': get_project_variant_tag_types(project), 'variantFunctionalTagTypes': get_json_for_variant_functional_data_tag_types(), }) return { 'projectsByGuid': {project.guid: project_json}, 'familiesByGuid': families_by_guid, 'individualsByGuid': individuals_by_guid, 'samplesByGuid': samples_by_guid, 'locusListsByGuid': locus_lists_by_guid, 'analysisGroupsByGuid': analysis_groups_by_guid, }
def _phenotips_view_handler(request, project_guid, individual_guid, url_template, permission_level=CAN_VIEW): """Requests the PhenoTips PDF for the given patient_id, and forwards PhenoTips' response to the client. Args: request: Django HTTP request object project_guid (string): project GUID for the seqr project containing this individual individual_guid (string): individual GUID for the seqr individual corresponding to the desired patient """ project = Project.objects.get(guid=project_guid) check_permissions(project, request.user, CAN_VIEW) individual = Individual.objects.get(guid=individual_guid) _create_patient_if_missing(project, individual) _set_phenotips_patient_id_if_missing(project, individual) # query string forwarding needed for PedigreeEditor button query_string = request.META["QUERY_STRING"] url = url_template.format(patient_id=individual.phenotips_patient_id, query_string=query_string) auth_tuple = _get_phenotips_username_and_password(request.user, project, permissions_level=permission_level) return proxy_request(request, url, headers={}, auth_tuple=auth_tuple, host=settings.PHENOTIPS_SERVER)
def update_project_handler(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 the following json structure: { 'form' : { 'name': <project name>, 'description': <project description>, } } Response body - will contain the following structure, representing the updated project: { 'projectsByGuid': { <projectGuid1> : { ... <project key-value pairs> ... } } } """ project = Project.objects.get(guid=project_guid) check_permissions(project, request.user, CAN_EDIT) request_json = json.loads(request.body) update_project_from_json(project, request_json, allow_unknown_keys=True) return create_json_response({ 'projectsByGuid': { project.guid: _get_json_for_project(project, request.user) }, })
def update_mme_submission(request, individual_guid): """ Create or update the submission for the given individual. """ individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user) submission_json = json.loads(request.body) submission_json.pop('individualGuid', {}) phenotypes = submission_json.pop('phenotypes', []) gene_variants = submission_json.pop('geneVariants', []) if not phenotypes and not gene_variants: return create_json_response({}, status=400, reason='Genotypes or phentoypes are required') if not submission_json.get('patient', {}).get('id'): return create_json_response({}, status=400, reason='Patient id is required') genomic_features = [] for gene_variant in gene_variants: if not gene_variant.get('geneId'): return create_json_response({}, status=400, reason='Gene id is required for genomic features') feature = {'gene': {'id': gene_variant['geneId']}} if 'numAlt' in gene_variant: feature['zygosity'] = gene_variant['numAlt'] % 2 if gene_variant.get('pos'): feature['variant'] = { 'alternateBases': gene_variant['alt'], 'referenceBases': gene_variant['ref'], 'referenceName': gene_variant['chrom'], 'start': gene_variant['pos'], 'assembly': gene_variant['genomeVersion'], } genomic_features.append(feature) submission_json['patient']['genomicFeatures'] = genomic_features submission_json['patient']['features'] = phenotypes response = requests.post(url=MME_ADD_INDIVIDUAL_URL, headers=MME_HEADERS, data=json.dumps(submission_json)) if response.status_code not in (200, 409): try: response_json = response.json() except Exception: response_json = {} return create_json_response(response_json, status=response.status_code, reason=response.content) submitted_date = datetime.now() individual.mme_submitted_data = submission_json individual.mme_submitted_date = submitted_date individual.mme_deleted_date = None individual.mme_deleted_by = None individual.save() # update the project contact information if anything new was added new_contact_names = set(submission_json['patient']['contact']['name'].split(',')) - set(project.mme_primary_data_owner.split(',')) new_contact_urls = set(submission_json['patient']['contact']['href'].replace('mailto:', '').split(',')) - set(project.mme_contact_url.replace('mailto:', '').split(',')) updates = {} if new_contact_names: updates['mme_primary_data_owner'] = '{},{}'.format(project.mme_primary_data_owner, ','.join(new_contact_names)) if new_contact_urls: updates['mme_contact_url'] = '{},{}'.format(project.mme_contact_url, ','.join(new_contact_urls)) if updates: update_seqr_model(project, **updates) # search for new matches return _search_individual_matches(individual, request.user)
def _check_results_permission(results_model, user): families = results_model.families.prefetch_related('project').all() projects = {family.project for family in families} for project in projects: check_permissions(project, user)