def create_saved_search_handler(request): request_json = json.loads(request.body) name = request_json.pop('name', None) if not name: return create_json_response({}, status=400, reason='"Name" is required') if request_json.get('inheritance', {}).get('filter', {}).get('genotype'): return create_json_response({}, status=400, reason='Saved searches cannot include custom genotype filters') try: saved_search, _ = VariantSearch.objects.get_or_create( search=request_json, created_by=request.user, ) except MultipleObjectsReturned: # Can't create a unique constraint on JSON field, so its possible that a duplicate gets made by accident dup_searches = VariantSearch.objects.filter( search=request_json, created_by=request.user, ) saved_search = dup_searches[0] for search in dup_searches: search.delete() saved_search.name = name saved_search.save() return create_json_response({ 'savedSearchesByGuid': { saved_search.guid: get_json_for_saved_search(saved_search, request.user) } })
def delete_saved_search_handler(request, saved_search_guid): search = VariantSearch.objects.get(guid=saved_search_guid) if search.created_by != request.user: return create_json_response({}, status=403, reason='User does not have permission to delete this search') search.delete() return create_json_response({'savedSearchesByGuid': {saved_search_guid: None}})
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_project_handler(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) name = request_json.get('name') if not name: return create_json_response({}, status=400, reason="'Name' cannot be blank") description = request_json.get('description', '') genome_version = request_json.get('genomeVersion') #if not created: # return create_json_response({}, status=400, reason="A project named '%(name)s' already exists" % locals()) project = create_project(name, description=description, genome_version=genome_version, user=request.user) return create_json_response({ 'projectsByGuid': { project.guid: _get_json_for_project(project, request.user) }, })
def delete_individuals_handler(request, project_guid): """Delete one or more Individual records. Args: request (object): Django HTTP Request object. project_guid (string): GUID of project that contains these individuals. Request: body should be a json dictionary that contains a 'recordIdsToDelete' list of individual GUIDs to delete - for example: { 'form': { 'recordIdsToDelete': [ <individualGuid1>, <individualGuid2>, ... } } } Response: json dictionary with the deleted GUIDs mapped to None: { <individualGuid1> : None, <individualGuid2> : None, ... } """ # validate request project = get_project_and_check_permissions(project_guid, request.user, CAN_EDIT) request_json = json.loads(request.body) individuals_list = request_json.get('individuals') if individuals_list is None: return create_json_response( {}, status=400, reason="Invalid request: 'individuals' not in request_json") logger.info("delete_individuals_handler %s", request_json) individual_guids_to_delete = [ind['individualGuid'] for ind in individuals_list] # delete the individuals families_with_deleted_individuals = delete_individuals(project, individual_guids_to_delete) deleted_individuals_by_guid = { individual_guid: None for individual_guid in individual_guids_to_delete } families_by_guid = { family.guid: _get_json_for_family(family, request.user, add_individual_guids_field=True) for family in families_with_deleted_individuals } # families whose list of individuals may have changed # send response return create_json_response({ 'individualsByGuid': deleted_individuals_by_guid, 'familiesByGuid': families_by_guid, })
def save_temp_file(request): try: uploaded_file_id, filename, json_records = save_uploaded_file(request) except Exception as e: return create_json_response({'errors': [e.message]}, status=400) response = {'uploadedFileId': uploaded_file_id} if request.GET.get('parsedData'): response['parsedData'] = json_records else: response['info'] = ['Parsed {num_rows} rows from {filename}'.format(num_rows=len(json_records), filename=filename)] return create_json_response(response)
def locus_lists(request): locus_lists = LocusList.objects.filter(Q(is_public=True) | Q(created_by=request.user)) locus_lists_json = get_json_for_locus_lists(locus_lists, request.user) return create_json_response({ 'locusListsByGuid': {locus_list['locusListGuid']: locus_list for locus_list in locus_lists_json} })
def save_individuals_table_handler(request, project_guid, upload_file_id): """Handler for 'save' requests to apply Individual tables previously uploaded through receive_individuals_table(..) Args: request (object): Django request object project_guid (string): project GUID uploadedFileId (string): a token sent to the client by receive_individuals_table(..) """ project = get_project_and_check_permissions(project_guid, request.user) json_records = load_uploaded_file(upload_file_id) updated_families, updated_individuals = add_or_update_individuals_and_families( project, individual_records=json_records, user=request.user ) # edit individuals individuals = _get_json_for_individuals(updated_individuals, request.user, add_sample_guids_field=True) individuals_by_guid = {individual['individualGuid']: individual for individual in individuals} families = _get_json_for_families(updated_families, request.user, add_individual_guids_field=True) families_by_guid = {family['familyGuid']: family for family in families} updated_families_and_individuals_by_guid = { 'individualsByGuid': individuals_by_guid, 'familiesByGuid': families_by_guid, } return create_json_response(updated_families_and_individuals_by_guid)
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 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_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 mme_submissions(request): individuals = Individual.objects.filter( mme_submitted_date__isnull=False, mme_deleted_date__isnull=True, ).prefetch_related('family').prefetch_related('family__project') hpo_terms_by_id, genes_by_id, gene_symbols_to_ids = get_mme_genes_phenotypes([i.mme_submitted_data for i in individuals]) submissions = [] for individual in individuals: submitted_data = parse_mme_patient(individual.mme_submitted_data, hpo_terms_by_id, gene_symbols_to_ids) submissions.append({ 'projectGuid': individual.family.project.guid, 'familyGuid': individual.family.guid, 'individualGuid': individual.guid, 'individualId': individual.individual_id, 'mmeSubmittedDate': individual.mme_submitted_date, 'mmeLabel': individual.mme_submitted_data['patient'].get('label'), 'mmeSubmittedData': submitted_data, 'geneSymbols': ','.join({genes_by_id.get(gv['geneId'], {}).get('geneSymbol') for gv in submitted_data['geneVariants']}) }) return create_json_response({ 'submissions': submissions, 'genesById': genes_by_id, })
def _search_individual_matches(individual, user): patient_data = individual.mme_submitted_data if not patient_data: return create_json_response( {}, status=404, reason='No matchmaker submission found for {}'.format(individual.individual_id), ) local_result = requests.post(url=MME_LOCAL_MATCH_URL, headers=MME_HEADERS, data=json.dumps(patient_data)) if local_result.status_code != 200: try: response_json = local_result.json() except Exception: response_json = {} return create_json_response(response_json, status=local_result.status_code, reason='Error in local match') external_result = requests.post(url=MME_EXTERNAL_MATCH_URL, headers=MME_HEADERS, data=json.dumps(patient_data)) if external_result.status_code != 200: try: response_json = external_result.json() except Exception: response_json = {} return create_json_response(response_json, status=external_result.status_code, reason='Error in external match') results = local_result.json()['results'] + external_result.json()['results'] saved_results = { result.result_data['patient']['id']: result for result in MatchmakerResult.objects.filter(individual=individual) } new_results = [] for result in results: saved_result = saved_results.get(result['patient']['id']) if not saved_result: saved_result = MatchmakerResult.objects.create( individual=individual, result_data=result, last_modified_by=user, ) new_results.append(result) saved_results[result['patient']['id']] = saved_result if new_results: _generate_slack_notification_for_seqr_match(individual, new_results) logger.info('Found {} matches for {} ({} new)'.format(len(results), individual.individual_id, len(new_results))) return _parse_mme_results(individual, saved_results.values())
def query_variants_handler(request, search_hash): """Search variants. """ page = int(request.GET.get('page') or 1) per_page = int(request.GET.get('per_page') or 100) sort = request.GET.get('sort') or XPOS_SORT_KEY if sort == PATHOGENICTY_SORT_KEY and request.user.is_staff: sort = PATHOGENICTY_HGMD_SORT_KEY results_model = VariantSearchResults.objects.filter(search_hash=search_hash).first() if not results_model: if not request.body: return create_json_response({}, status=400, reason='Invalid search hash: {}'.format(search_hash)) search_context = json.loads(request.body) project_families = search_context.get('projectFamilies') if not project_families: return create_json_response({}, status=400, reason='Invalid search: no projects/ families specified') search_dict = search_context.get('search', {}) search_model = VariantSearch.objects.filter(search=search_dict).filter(Q(created_by=request.user) | Q(name__isnull=False)).first() if not search_model: search_model = VariantSearch.objects.create(created_by=request.user, search=search_dict) results_model = VariantSearchResults.objects.create(search_hash=search_hash, variant_search=search_model) all_families = set() for project_family in project_families: all_families.update(project_family['familyGuids']) results_model.families.set(Family.objects.filter(guid__in=all_families)) _check_results_permission(results_model, request.user) try: variants, total_results = get_es_variants(results_model, sort=sort, page=page, num_results=per_page) except InvalidIndexException as e: return create_json_response({}, status=400, reason=e.message) except ConnectionTimeout as e: return create_json_response({}, status=504, reason='Query Time Out') response = _process_variants(variants, results_model.families.all()) response['search'] = _get_search_context(results_model) response['search']['totalResults'] = total_results return create_json_response(response)
def update_analysis_group_handler(request, project_guid, analysis_group_guid=None): project = get_project_and_check_permissions(project_guid, request.user, permission_level=CAN_EDIT) request_json = json.loads(request.body) missing_fields = [field for field in REQUIRED_FIELDS.keys() if not request_json.get(field)] if missing_fields: return create_json_response( {}, status=400, reason='Missing required field(s): {missing_field_names}'.format( missing_field_names=', '.join([REQUIRED_FIELDS[field] for field in missing_fields]) )) families = Family.objects.filter(guid__in=request_json['familyGuids']).only('guid') if len(families) != len(request_json['familyGuids']): return create_json_response( {}, status=400, reason='The following families do not exist: {missing_families}'.format( missing_families=', '.join(set(request_json['familyGuids']) - set([family.guid for family in families])) )) if analysis_group_guid: analysis_group = AnalysisGroup.objects.get(guid=analysis_group_guid, project=project) update_model_from_json(analysis_group, request_json, allow_unknown_keys=True) else: try: analysis_group = create_seqr_model( AnalysisGroup, project=project, name=request_json['name'], description=request_json.get('description'), created_by=request.user, ) except IntegrityError: return create_json_response( {}, status=400, reason='An analysis group named "{name}" already exists for project "{project}"'.format( name=request_json['name'], project=project.name )) analysis_group.families.set(families) base_family_group = find_matching_xbrowse_model(analysis_group) if base_family_group: base_family_group.families.set(BaseFamily.objects.filter(seqr_family__in=families)) return create_json_response({ 'analysisGroupsByGuid': { analysis_group.guid: get_json_for_analysis_group(analysis_group, project_guid=project_guid) }, })
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 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 delete_gene_note_handler(request, gene_id, note_guid): note = GeneNote.objects.get(guid=note_guid) if not _can_edit_note(note, request.user): raise PermissionDenied("User does not have permission to delete this note") delete_seqr_model(note) return create_json_response({'genesById': {gene_id: { 'notes': _get_gene_notes(gene_id, request.user) }}})
def process_exception(request, exception): if request.path.startswith('/api'): exception_json = {'message': str(exception.message)} traceback_message = traceback.format_exc() logger.error(traceback_message) if hasattr(settings, 'DEBUG'): exception_json['traceback'] = traceback_message.split('\n') return create_json_response(exception_json, status=500) return None
def search_context_handler(request): """Search variants. """ response = _get_saved_searches(request.user) project_guid = request.GET.get('projectGuid') if project_guid: project = Project.objects.get(guid=project_guid) elif request.GET.get('familyGuid'): project = Project.objects.get(family__guid=request.GET.get('familyGuid')) elif request.GET.get('analysisGroupGuid'): project = Project.objects.get(analysisgroup__guid=request.GET.get('analysisGroupGuid')) else: return create_json_response({}, status=400, reason='Invalid query params: {}'.format(json.dumps(request.GET))) response.update(_get_project_details(project, request.user)) return create_json_response(response)
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_saved_search_handler(request, saved_search_guid): search = VariantSearch.objects.get(guid=saved_search_guid) if search.created_by != request.user: return create_json_response({}, status=403, reason='User does not have permission to edit this search') request_json = json.loads(request.body) name = request_json.pop('name', None) if not name: return create_json_response({}, status=400, reason='"Name" is required') search.name = name search.save() return create_json_response({ 'savedSearchesByGuid': { saved_search_guid: get_json_for_saved_search(search, request.user) } })
def update_locus_list_handler(request, locus_list_guid): locus_list = LocusList.objects.get(guid=locus_list_guid) check_object_permissions(locus_list, request.user, permission_level=CAN_EDIT) request_json = json.loads(request.body) genes_by_id, intervals, invalid_items = parse_locus_list_items(request_json) if invalid_items and not request_json.get('ignoreInvalidItems'): return create_json_response({'invalidLocusListItems': invalid_items}, status=400, reason=INVALID_ITEMS_ERROR) update_model_from_json(locus_list, request_json, allow_unknown_keys=True) if genes_by_id is not None: _update_locus_list_items(locus_list, genes_by_id, intervals, request_json, request.user) return create_json_response({ 'locusListsByGuid': {locus_list.guid: get_json_for_locus_list(locus_list, request.user)}, 'genesById': genes_by_id or {}, })
def delete_families_handler(request, project_guid): """Edit or delete one or more Individual records. Args: project_guid (string): GUID of project that contains these individuals. """ project = get_project_and_check_permissions(project_guid, request.user, CAN_EDIT) request_json = json.loads(request.body) logger.info("delete_families_handler %s", request_json) families_to_delete = request_json.get('families') if families_to_delete is None: return create_json_response( {}, status=400, reason="'recordIdsToDelete' not specified") family_guids_to_delete = [f['familyGuid'] for f in families_to_delete] # delete individuals 1st individual_guids_to_delete = [i.guid for i in Individual.objects.filter( family__project=project, family__guid__in=family_guids_to_delete)] delete_individuals(project, individual_guids_to_delete) # delete families for family in Family.objects.filter(project=project, guid__in=family_guids_to_delete): base_family = BaseFamily.objects.get( project__project_id=project.deprecated_project_id, family_id=family.family_id) base_family.delete() family.delete() # send response return create_json_response({ 'individualsByGuid': { individual_guid: None for individual_guid in individual_guids_to_delete }, 'familiesByGuid': { family_guid: None for family_guid in family_guids_to_delete }, })
def query_single_variant_handler(request, variant_id): """Search variants. """ families = Family.objects.filter(guid=request.GET.get('familyGuid')) variant = get_single_es_variant(families, variant_id) response = _process_variants([variant], families) response.update(_get_project_details(families.first().project, request.user)) return create_json_response(response)
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_gene_note_handler(request, gene_id, note_guid): note = GeneNote.objects.get(guid=note_guid) if not _can_edit_note(note, request.user): raise PermissionDenied("User does not have permission to edit this note") request_json = json.loads(request.body) update_model_from_json(note, request_json, allow_unknown_keys=True) return create_json_response({'genesById': {gene_id: { 'notes': _get_gene_notes(gene_id, request.user) }}})
def locus_list_info(request, locus_list_guid): locus_list = LocusList.objects.get(guid=locus_list_guid) check_public_object_permissions(locus_list, request.user) locus_list_json = get_json_for_locus_list(locus_list, request.user) gene_ids = [item['geneId'] for item in locus_list_json['items'] if item.get('geneId')] return create_json_response({ 'locusListsByGuid': {locus_list_guid: locus_list_json}, 'genesById': get_genes(gene_ids, add_dbnsfp=True, add_omim=True, add_constraints=True) })
def create_gene_note_handler(request, gene_id): request_json = json.loads(request.body) create_seqr_model( GeneNote, note=request_json.get('note'), gene_id=gene_id, created_by=request.user, ) return create_json_response({'genesById': {gene_id: { 'notes': _get_gene_notes(gene_id, request.user) }}})
def edit_families_handler(request, project_guid): """Edit or one or more Family records. Args: project_guid (string): GUID of project that contains these individuals. """ request_json = json.loads(request.body) if request_json.get('uploadedFileId'): modified_families = load_uploaded_file(request_json.get('uploadedFileId')) else: modified_families = request_json.get('families') if modified_families is None: return create_json_response( {}, status=400, reason="'families' not specified") project = get_project_and_check_permissions(project_guid, request.user, CAN_EDIT) updated_families = [] for fields in modified_families: if fields.get('familyGuid'): family = Family.objects.get(project=project, guid=fields['familyGuid']) elif fields.get(PREVIOUS_FAMILY_ID_FIELD): family = Family.objects.get(project=project, family_id=fields[PREVIOUS_FAMILY_ID_FIELD]) else: family, _ = get_or_create_seqr_model(Family, project=project, family_id=fields[FAMILY_ID_FIELD]) update_family_from_json(family, fields, user=request.user, allow_unknown_keys=True) updated_families.append(family) updated_families_by_guid = { 'familiesByGuid': { family.guid: _get_json_for_family(family, request.user, add_individual_guids_field=True) for family in updated_families } } return create_json_response(updated_families_by_guid)
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 delete_families_handler(request, project_guid): """Edit or delete one or more Individual records. Args: project_guid (string): GUID of project that contains these individuals. """ project = get_project_and_check_permissions(project_guid, request.user, can_edit=True) request_json = json.loads(request.body) logger.info("delete_families_handler %s", request_json) families_to_delete = request_json.get('families') if families_to_delete is None: return create_json_response( {}, status=400, reason="'recordIdsToDelete' not specified") family_guids_to_delete = [f['familyGuid'] for f in families_to_delete] # delete individuals 1st individual_guids_to_delete = [i.guid for i in Individual.objects.filter( family__project=project, family__guid__in=family_guids_to_delete)] delete_individuals(project, individual_guids_to_delete) # delete families Family.objects.filter(project=project, guid__in=family_guids_to_delete).delete() # send response return create_json_response({ 'individualsByGuid': { individual_guid: None for individual_guid in individual_guids_to_delete }, 'familiesByGuid': { family_guid: None for family_guid in family_guids_to_delete }, })
def send_mme_contact_email(request, matchmaker_result_guid): """ Sends the given email and updates the contacted status for the match Args: matchmaker_result_guid Returns: Status code and results """ result = MatchmakerResult.objects.get(guid=matchmaker_result_guid) check_mme_permissions(result.submission, request.user) request_json = json.loads(request.body) email_message = EmailMessage( subject=request_json['subject'], body=request_json['body'], to=map(lambda s: s.strip(), request_json['to'].split(',')), from_email=MME_DEFAULT_CONTACT_EMAIL, ) try: email_message.send() except Exception as e: message = e.message json_body = {} if hasattr(e, 'response'): message = e.response.content try: json_body = e.response.json() except Exception: json_body = {'message':message} return create_json_response(json_body, status=getattr(e, 'status_code', 400), reason=message) update_model_from_json(result, {'weContacted': True}) return create_json_response({ 'mmeResultsByGuid': {matchmaker_result_guid: {'matchStatus': _get_json_for_model(result)}}, })
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_project_permissions(family.project, request.user, can_edit=True) 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 = next(iter((request.FILES.values()))) update_model_from_json(family, {'pedigree_image': pedigree_image}, request.user) return create_json_response({ family.guid: _get_json_for_family(family, request.user) })
def locus_lists(request): locus_list_models = LocusList.objects.filter( Q(is_public=True) | Q(created_by=request.user)).annotate(num_projects=Count('projects')) locus_lists_json = get_json_for_locus_lists(locus_list_models, request.user, include_project_count=True) return create_json_response({ 'locusListsByGuid': { locus_list['locusListGuid']: locus_list for locus_list in locus_lists_json } })
def create_gene_note_handler(request, gene_id): request_json = json.loads(request.body) GeneNote.objects.create( note=request_json.get('note'), gene_id=gene_id, created_by=request.user, ) return create_json_response({ 'genesById': { gene_id: { 'notes': _get_gene_notes(gene_id, request.user) } } })
def _update_existing_user(user, project, request_json): project.can_view_group.user_set.add(user) if request_json.get('hasEditPermissions'): project.can_edit_group.user_set.add(user) else: project.can_edit_group.user_set.remove(user) return create_json_response({ 'projectsByGuid': { project.guid: { 'collaborators': get_json_for_project_collaborator_list(user, project) } } })
def delete_project_collaborator(request, project_guid, username): project = get_project_and_check_permissions(project_guid, request.user, permission_level=CAN_EDIT) user = User.objects.get(username=username) project.can_view_group.user_set.remove(user) project.can_edit_group.user_set.remove(user) if project.deprecated_project_id: base_project = BaseProject.objects.filter(project_id=project.deprecated_project_id).first() if base_project: ProjectCollaborator.objects.get(user=user, project=base_project).delete() return create_json_response({ 'projectsByGuid': {project_guid: {'collaborators': get_json_for_project_collaborator_list(project)}} })
def query_variants_handler(request, search_hash): """Search variants. """ page = int(request.GET.get('page') or 1) per_page = int(request.GET.get('per_page') or 100) sort = request.GET.get('sort') or XPOS_SORT_KEY if sort == PATHOGENICTY_SORT_KEY and request.user.is_staff: sort = PATHOGENICTY_HGMD_SORT_KEY try: results_model = _get_or_create_results_model( search_hash, json.loads(request.body or '{}'), request.user) except Exception as e: return create_json_response({'error': e.message}, status=400, reason=e.message) _check_results_permission(results_model, request.user) try: variants, total_results = get_es_variants(results_model, sort=sort, page=page, num_results=per_page) except InvalidIndexException as e: return create_json_response({'error': e.message}, status=400, reason=e.message) except ConnectionTimeout as e: return create_json_response({}, status=504, reason='Query Time Out') response = _process_variants(variants, results_model.families.all()) response['search'] = _get_search_context(results_model) response['search']['totalResults'] = total_results return create_json_response(response)
def update_locus_list_handler(request, locus_list_guid): locus_list = LocusList.objects.get(guid=locus_list_guid) check_user_created_object_permissions(locus_list, request.user) request_json = json.loads(request.body) genes_by_id, intervals, invalid_items = parse_locus_list_items( request_json) if invalid_items and not request_json.get('ignoreInvalidItems'): return create_json_response({'invalidLocusListItems': invalid_items}, status=400, reason=INVALID_ITEMS_ERROR) update_model_from_json(locus_list, request_json, allow_unknown_keys=True) if genes_by_id is not None: _update_locus_list_items(locus_list, genes_by_id, intervals, request_json) return create_json_response({ 'locusListsByGuid': { locus_list.guid: get_json_for_locus_list(locus_list, request.user) }, 'genesById': genes_by_id or {}, })
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.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_project_handler(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) missing_fields = [field for field in ['name', 'genomeVersion'] if not request_json.get(field)] if missing_fields: error = 'Field(s) "{}" are required'.format(', '.join(missing_fields)) return create_json_response({'error': error}, status=400, reason=error) project_args = { 'name': request_json['name'], 'genome_version': request_json['genomeVersion'], 'description': request_json.get('description', ''), } project = create_model_from_json(Project, project_args, user=request.user) if ANALYST_PROJECT_CATEGORY: ProjectCategory.objects.get(name=ANALYST_PROJECT_CATEGORY).projects.add(project) return create_json_response({ 'projectsByGuid': { project.guid: _get_json_for_project(project, request.user) }, })
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 saved_variant_data(request, project_guid, variant_guid=None): project = get_project_and_check_permissions(project_guid, request.user) variants = {} variant_query = SavedVariant.objects.filter(project=project)\ .select_related('family')\ .only('xpos_start', 'ref', 'alt', 'saved_variant_json', 'family__guid', 'guid')\ .prefetch_related('varianttag_set', 'varianttag_set__created_by', 'varianttag_set__variant_tag_type', 'variantfunctionaldata_set', 'variantfunctionaldata_set__created_by', 'variantnote_set', 'variantnote_set__created_by') if request.GET.get('family'): variant_query = variant_query.filter(family__guid=request.GET.get('family')) if variant_guid: variant_query = variant_query.filter(guid=variant_guid) if variant_query.count() < 1: return create_json_response({}, status=404, reason='Variant {} not found'.format(variant_guid)) for saved_variant in variant_query: variant = get_json_for_saved_variant(saved_variant, add_tags=True) if variant['tags'] or variant['notes']: variant_json = json.loads(saved_variant.saved_variant_json or '{}') variant.update(_variant_details(variant_json, request.user)) variants[variant['variantId']] = variant return create_json_response({'savedVariants': variants})
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 GUID: %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.select_related('family').filter( family__project=project): # filter out individuals that were never in case review 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 project_page_data(request, project_guid): """Returns a JSON object containing information used by the project page: :: json_response = { 'user': {..}, 'familiesByGuid': {..}, 'individualsByGuid': {..}, 'samplesByGuid': {..}, 'datasetsByGuid': {..}, } Args: project_guid (string): GUID of the Project to retrieve data for. """ project = _get_project_and_check_permissions(project_guid, request.user) cursor = connection.cursor() families_by_guid, individuals_by_guid = _retrieve_families_and_individuals(cursor, project.guid) samples_by_guid, datasets_by_guid = _retrieve_samples(cursor, project.guid, individuals_by_guid) cursor.close() project_json = _get_json_for_project(project, request.user) project_json['collaborators'] = _get_json_for_collaborator_list(project) project_json['locusLists'] = _get_json_for_locus_lists(project) project_json['variantTagTypes'] = _get_json_for_variant_tag_types(project) #project_json['referencePopulations'] = _get_json_for_reference_populations(project) # gene search will be deprecated once the new database is online. project_json['hasGeneSearch'] = _has_gene_search(project) user_json = _get_json_for_user(request.user) user_json['hasEditPermissions'] = request.user.is_staff or request.user.has_perm(CAN_EDIT, project) user_json['hasViewPermissions'] = user_json['hasEditPermissions'] or request.user.has_perm(CAN_VIEW, project) json_response = { 'user': user_json, 'project': project_json, 'familiesByGuid': families_by_guid, 'individualsByGuid': individuals_by_guid, 'samplesByGuid': samples_by_guid, 'datasetsByGuid': datasets_by_guid, } return create_json_response(json_response)
def delete_project_handler(request, project_guid): """Delete project - request handler. Args: project_guid (string): GUID of the project to delete """ project = get_project_and_check_permissions(project_guid, request.user, is_owner=True) _delete_project(project) return create_json_response({ 'projectsByGuid': { project.guid: None }, })
def update_gene_note_handler(request, gene_id, note_guid): note = GeneNote.objects.get(guid=note_guid) if not _can_edit_note(note, request.user): raise PermissionDenied( "User does not have permission to edit this note") request_json = json.loads(request.body) update_model_from_json(note, request_json, allow_unknown_keys=True) return create_json_response({ 'genesById': { gene_id: { 'notes': _get_gene_notes(gene_id, request.user) } } })
def update_variant_main_transcript(request, variant_guid, transcript_id): saved_variant = SavedVariant.objects.get(guid=variant_guid) check_project_permissions(saved_variant.family.project, request.user, can_edit=True) saved_variant.selected_main_transcript_id = transcript_id saved_variant.save() return create_json_response({ 'savedVariantsByGuid': { variant_guid: { 'selectedMainTranscriptId': transcript_id } } })
def update_saved_variant_json(request, project_guid): project = get_project_and_check_permissions(project_guid, request.user, can_edit=True) reset_cached_search_results(project) try: updated_saved_variant_guids = update_project_saved_variant_json( project, user=request.user) except Exception as e: logger.error('Unable to reset saved variant json for {}: {}'.format( project_guid, e)) updated_saved_variant_guids = [] return create_json_response( {variant_guid: None for variant_guid in updated_saved_variant_guids})
def get_hpo_terms(request, hpo_parent_id): """ Get all the HPO Terms with the given parent ID """ return create_json_response({ hpo_parent_id: { hpo.hpo_id: { 'id': hpo.hpo_id, 'category': hpo.category_id, 'label': hpo.name } for hpo in HumanPhenotypeOntology.objects.filter( parent_id=hpo_parent_id) } })
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_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_project_permissions(family.project, request.user, can_edit=False) FamilyAnalysedBy.objects.create(family=family, created_by=request.user) return create_json_response( {family.guid: _get_json_for_family(family, 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({ variant_guid: { 'notes': [ get_json_for_variant_note(tag) for tag in saved_variant.variantnote_set.all() ] } })
def save_case_review_status(request): """Updates the `case_review_status` of one or more individuals. HTTP POST Request body - should contain json: { form: { <individualGuid1> : <case review status>, <individualGuid2> : <case review status>, .. } } Response body - will be json with the following structure, representing the created project: { <individualGuid1> : { ... <individual key-value pairs> ... }, } """ requestJSON = json.loads(request.body) responseJSON = {} for individual_guid, new_case_review_status in requestJSON['form'].items(): i = Individual.objects.get(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: base_project = BaseProject.objects.filter( project_id=i.family.project.deprecated_project_id) if base_project: base_project = base_project[0] 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 Exception as e: raise return create_json_response(responseJSON)
def query_variants(request, project_guid): """Search variants Args: project_guid (string): GUID of the project to query HTTP POST Response body - will be json with the delete projectGuid mapped to the special 'DELETE' keyword: { 'projectsByGuid': { <projectGuid1> : ... } } """ project = Project.objects.get(guid=project_guid) # check permissions if not request.user.has_perm(CAN_VIEW, 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") results = requests.post('http://localhost:6060/', json={ "page": 1, "limit": 100, "genotype_filters": { "1877nih": { "num_alt": 1 }, "22067nih": { "num_alt": 2 } } }) print(results.status_code) results = json.loads(results.text) # TODO delete Family, Individual, and other objects under this project return create_json_response({ 'variants': results, })
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 delete_project_locus_lists(request, project_guid): project = get_project_and_check_permissions(project_guid, request.user, CAN_EDIT) request_json = json.loads(request.body) locus_lists = LocusList.objects.filter( guid__in=request_json['locusListGuids']) for locus_list in locus_lists: locus_list.projects.remove(project) locus_list.save() return create_json_response({ 'locusListGuids': [ locus_list['locusListGuid'] for locus_list in _get_sorted_project_locus_lists( project, request.user) ], })
def delete_project_collaborator(request, project_guid, username): project = get_project_and_check_permissions(project_guid, request.user, can_edit=True) user = User.objects.get(username=username) project.can_view_group.user_set.remove(user) project.can_edit_group.user_set.remove(user) return create_json_response({ 'projectsByGuid': { project_guid: { 'collaborators': get_json_for_project_collaborator_list(request.user, project) } } })