def test_json_for_family(self): family = Family.objects.first() json = _get_json_for_family(family) family_fields = { 'projectGuid', 'familyGuid', 'analysedBy', 'pedigreeImage', 'familyId', 'displayName', 'description', 'analysisNotes', 'analysisSummary', 'causalInheritanceMode', 'analysisStatus', 'pedigreeImage', 'createdDate', 'codedPhenotype', 'postDiscoveryOmimNumber', } self.assertSetEqual(set(json.keys()), family_fields) family_fields.update({ 'internalAnalysisStatus', 'internalCaseReviewNotes', 'internalCaseReviewSummary', 'individualGuids', }) user = User.objects.filter(is_staff=True).first() json = _get_json_for_family(family, user, add_individual_guids_field=True) self.assertSetEqual(set(json.keys()), family_fields)
def test_json_for_family(self, mock_analyst_group): family = Family.objects.filter(project__has_case_review=False).first() json = _get_json_for_family(family) self.assertSetEqual(set(json.keys()), FAMILY_FIELDS) user = User.objects.get(username='******') json = _get_json_for_family(family, user) self.assertSetEqual(set(json.keys()), FAMILY_FIELDS) mock_analyst_group.__bool__.return_value = True mock_analyst_group.resolve_expression.return_value = 'analysts' json = _get_json_for_family(family, user, add_individual_guids_field=True) self.assertSetEqual(set(json.keys()), INTERNAL_FAMILY_FIELDS) case_review_family = Family.objects.filter( project__has_case_review=True).first() json = _get_json_for_family(case_review_family) self.assertSetEqual(set(json.keys()), FAMILY_FIELDS) fields = set() fields.update(INTERNAL_FAMILY_FIELDS) fields.update(CASE_REVIEW_FAMILY_FIELDS) json = _get_json_for_family(case_review_family, user, add_individual_guids_field=True) self.assertSetEqual(set(json.keys()), fields)
def test_json_for_family(self): family = Family.objects.first() json = _get_json_for_family(family) self.assertSetEqual(set(json.keys()), FAMILY_FIELDS) user = User.objects.filter(is_staff=True).first() json = _get_json_for_family(family, user, add_individual_guids_field=True) self.assertSetEqual(set(json.keys()), INTERNAL_FAMILY_FIELDS)
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_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()))) family.pedigree_image = pedigree_image family.save() return create_json_response( {family.guid: _get_json_for_family(family, request.user)})
def save_internal_case_review_summary(request, family_guid): """Updates the `internal_case_review_summary` field for the given family. Args: family_guid (string): GUID of the family. """ family = Family.objects.get(guid=family_guid) request_json = json.loads(request.body) if "value" not in request_json: raise ValueError("Request is missing 'value' key: %s" % (request.body, )) family.internal_case_review_summary = request_json['value'] 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_summary = request_json['value'] base_f.save() except: raise return create_json_response({ family.guid: _get_json_for_family(family, request.user, add_individual_guids_field=True) })
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 if not request.user.is_staff and not request.user.has_perm(CAN_EDIT, project): raise PermissionDenied("%s does not have EDIT permissions for %s" % (request.user, project)) request_json = json.loads(request.body) if "value" not in request_json: raise ValueError("Request is missing 'value' key") value = request_json['value'] family_json = {field_name: value} update_family_from_json(family, family_json) _deprecated_update_original_family_record(project, family, field_name, value) return create_json_response({ family.guid: _get_json_for_family(family, 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) # assigned_analyst can be edited by anyone with access to the project check_project_permissions(family.project, request.user, can_edit=False) 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 family.assigned_analyst = assigned_analyst family.save() return create_json_response( {family.guid: _get_json_for_family(family, 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 test_json_for_family(self): family = Family.objects.first() json = _get_json_for_family(family) family_fields = { 'projectGuid', 'familyGuid', 'analysedBy', 'pedigreeImage', 'familyId', 'displayName', 'description', 'analysisNotes', 'analysisSummary', 'causalInheritanceMode', 'analysisStatus', 'pedigreeImage', 'createdDate', 'codedPhenotype', 'postDiscoveryOmimNumber', 'pubmedIds', } self.assertSetEqual(set(json.keys()), family_fields) family_fields.update({ 'internalAnalysisStatus', 'internalCaseReviewNotes', 'internalCaseReviewSummary', 'individualGuids', }) user = User.objects.filter(is_staff=True).first() json = _get_json_for_family(family, user, add_individual_guids_field=True) self.assertSetEqual(set(json.keys()), family_fields)
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 edit_families_handler(request, project_guid): """Edit or one or more Family records. Args: project_guid (string): GUID of project that contains these individuals. """ project = get_project_and_check_pm_permissions(project_guid, request.user) 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") 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_model_from_json( Family, { 'project': project, 'family_id': fields[FAMILY_ID_FIELD] }, update_json=None, user=request.user) 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 edit_families_handler(request, project_guid): """Edit or one or more Family 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) if 'form' not in request_json: return create_json_response( {}, status=400, reason="Invalid request: 'form' key not specified") form_data = request_json['form'] modified_families_by_guid = form_data.get('modifiedFamilies') if modified_families_by_guid is None: return create_json_response( {}, status=400, reason="'modifiedIndividuals' not specified") # TODO more validation #errors, warnings = validate_fam_file_records(modified_individuals_list) #if errors: # return create_json_response({'errors': errors, 'warnings': warnings}) updated_families = [] for familyGuid, fields in modified_families_by_guid.items(): family = Family.objects.get(project=project, guid=familyGuid) update_family_from_json(family, fields) updated_families.append(family) for key, value in fields.items(): # TODO do this more efficiently _deprecated_update_original_family_field(project, family, key, value) 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 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_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 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': {..}, } Args: project_guid (string): GUID of the project being case-reviewed. """ # get all families in this project project = get_project_and_check_permissions(project_guid, request.user) json_response = { 'user': _get_json_for_user(request.user), 'project': _get_json_for_project(project, request.user), 'familiesByGuid': {}, 'individualsByGuid': {}, } 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 family.guid not in json_response['familiesByGuid']: json_response['familiesByGuid'][ family.guid] = _get_json_for_family(family, request.user) json_response['familiesByGuid'][ family.guid]['individualGuids'] = [] json_response['individualsByGuid'][i.guid] = _get_json_for_individual( i, request.user) json_response['familiesByGuid'][family.guid]['individualGuids'].append( i.guid) return create_json_response(json_response)
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) add_family_analysed_by(request, data={ 'family_id': family.family_id, 'project_id': family.project.deprecated_project_id }) return create_json_response( {family.guid: _get_json_for_family(family, request.user)})
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_project_permissions(project, request.user, can_edit=True) 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 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 - can be edited by anyone with access to the project check_project_permissions(family.project, request.user) request_json = json.loads(request.body) update_family_from_json(family, request_json, user=request.user, allow_unknown_keys=True, immutable_keys=[ 'family_id', 'display_name', ]) return create_json_response({ family.guid: _get_json_for_family(family, request.user) })
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 save_internal_case_review_notes(request, family_guid): """Updates the `case_review_notes` field for the given family. Args: family_guid (string): GUID of the family. """ family = Family.objects.get(guid=family_guid) request_json = json.loads(request.body) if "value" not in request_json: raise ValueError("Request is missing 'value' key: %s" % (request.body, )) update_seqr_model(family, internal_case_review_notes=request_json['value']) return create_json_response({ family.guid: _get_json_for_family(family, request.user, add_individual_guids_field=True) })
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 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) serialized_file_path = _compute_serialized_file_path(upload_file_id) with gzip.open(serialized_file_path) as f: json_records = json.load(f) updated_families, updated_individuals = add_or_update_individuals_and_families( project, individual_records=json_records) os.remove(serialized_file_path) # edit individuals individuals_by_guid = { individual.guid: _get_json_for_individual(individual, request.user) for individual in updated_individuals } families_by_guid = { family.guid: _get_json_for_family(family, request.user, add_individual_guids_field=True) for family in updated_families } # families whose list of individuals may have changed 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 edit_individuals_handler(request, project_guid): """Modify 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 'individuals' list that includes the individuals to update, represented by dictionaries of their guid and fields to update - for example: { 'individuals': [ { 'individualGuid': <individualGuid1>, 'paternalId': <paternalId>, 'affected': 'A' }, { 'individualGuid': <individualGuid1>, 'sex': 'U' }, ... [ } Response: json dictionary representing the updated individual(s) like: { <individualGuid1> : { individualId: xxx, sex: xxx, affected: xxx, ...}, <individualGuid2> : { individualId: xxx, sex: xxx, affected: xxx, ...}, ... } """ project = get_project_and_check_permissions(project_guid, request.user, CAN_EDIT) request_json = json.loads(request.body) modified_individuals_list = request_json.get('individuals') if modified_individuals_list is None: return create_json_response( {}, status=400, reason="'individuals' not specified") update_individuals = {ind['individualGuid']: ind for ind in modified_individuals_list} update_individual_models = {ind.guid: ind for ind in Individual.objects.filter(guid__in=update_individuals.keys())} for modified_ind in modified_individuals_list: model = update_individual_models[modified_ind['individualGuid']] if modified_ind[JsonConstants.INDIVIDUAL_ID_COLUMN] != model.individual_id: modified_ind[JsonConstants.PREVIOUS_INDIVIDUAL_ID_COLUMN] = model.individual_id modified_family_ids = {ind.get('familyId') or ind['family']['familyId'] for ind in modified_individuals_list} modified_family_ids.update({ind.family.family_id for ind in update_individual_models.values()}) related_individuals = Individual.objects.filter( family__family_id__in=modified_family_ids, family__project=project).exclude(guid__in=update_individuals.keys()) related_individuals_json = _get_json_for_individuals(related_individuals, project_guid=project_guid, family_fields=['family_id']) individuals_list = modified_individuals_list + related_individuals_json # TODO more validation? errors, warnings = validate_fam_file_records(individuals_list, fail_on_warnings=True) if errors: return create_json_response({'errors': errors, 'warnings': warnings}, status=400, reason='Invalid updates') try: updated_families, updated_individuals = add_or_update_individuals_and_families( project, modified_individuals_list, user=request.user ) except Exception as e: return create_json_response({'errors': [e.message]}, status=400, reason='Invalid updates') individuals_by_guid = { individual.guid: _get_json_for_individual(individual, request.user) for individual in updated_individuals } families_by_guid = { family.guid: _get_json_for_family(family, request.user, add_individual_guids_field=True) for family in updated_families } return create_json_response({ 'individualsByGuid': individuals_by_guid, 'familiesByGuid': families_by_guid, })
def edit_individuals_handler(request, project_guid): """Modify 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 'modifiedIndividuals' dictionary that includes the individuals to update, mapped to the specific fields that should be updated for each individual - for example: { 'form': { 'modifiedIndividuals': { <individualGuid1>: { 'paternalId': <paternalId>, 'affected': 'A' }, <individualGuid2>: { 'sex': 'U' }, ... } } } Response: json dictionary representing the updated individual(s) like: { <individualGuid1> : { individualId: xxx, maternalId: xxx, paternalId: xxx, ...}, <individualGuid2> : { individualId: xxx, maternalId: xxx, paternalId: xxx, ...}, ... } """ project = get_project_and_check_permissions(project_guid, 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' key not specified") form_data = request_json['form'] modified_individuals_by_guid = form_data.get('modifiedIndividuals') if modified_individuals_by_guid is None: return create_json_response( {}, status=400, reason="'modifiedIndividuals' not specified") # edit individuals modified_individuals_list = list(modified_individuals_by_guid.values()) # TODO more validation errors, warnings = validate_fam_file_records(modified_individuals_list) if errors: return create_json_response({'errors': errors, 'warnings': warnings}) updated_families, updated_individuals = add_or_update_individuals_and_families( project, modified_individuals_list) individuals_by_guid = { individual.guid: _get_json_for_individual(individual, request.user) for individual in updated_individuals } families_by_guid = { family.guid: _get_json_for_family(family, request.user, add_individual_guids_field=True) for family in updated_families } # families whose list of individuals may have changed updated_individuals_by_guid = { 'individualsByGuid': individuals_by_guid, 'familiesByGuid': families_by_guid, } return create_json_response(updated_individuals_by_guid)
def variant_search_page_data(request, project_guid, family_guid): """Returns a JSON object containing information needed to display the variant search page :: json_response = { 'user': {..}, 'variants': [..], } Args: project_guid (string): GUID of the Project under case review. """ logger.info("project_guid: %s" % (project_guid,)) logger.info("family_guid: %s" % (family_guid,)) if family_guid is not None: # single-family search mode family = Family.objects.get(guid=family_guid) # TODO handle family-not-found project = family.project check_permissions(project, request.user, CAN_VIEW) project_guids = [project.guid] family_guids = [family_guid] else: # all-families-in-a-project search mode family = None family_guids = None if project_guid is not None: project = Project.objects.get(guid=project_guid) # TODO handle project-not-found # check permissions check_permissions(project, request.user, CAN_VIEW) project_guids = [project.guid] else: # all projects search mode permissions to access project = None project_guids = [p.guid for p in get_projects_user_can_view(request.user)] # get all datasets dataset_info = _retrieve_datasets( project_guids=project_guids, family_guids=family_guids, individual_guids=None, sample_types=None, analysis_types=None, only_loaded_datasets=True ) # retrieve search params from hash or use default values search_params_hash = request.GET.get("h") if search_params_hash is not None: search_params = {} # TODO retrieve search params for hash raise ValueError("Not implemented") else: search_params = { 'dataset_guids': [], 'project_guids': project_guids, 'family_guids': [], } # TODO adjust search params that are no-longer valid json_response = { 'user': _get_json_for_user(request.user), 'project': _get_json_for_project(project, request.user) if project is not None else {}, 'family': _get_json_for_family(family, request.user) if family is not None else {}, 'variants': {}, 'datasets': dataset_info, } return create_json_response(json_response)