def delete_project_locus_lists(request, project_guid): project = get_project_and_check_permissions(project_guid, request.user, CAN_EDIT) xbrowse_project = find_matching_xbrowse_model(project) request_json = json.loads(request.body) locus_lists = LocusList.objects.filter(guid__in=request_json['locusListGuids']) for locus_list in locus_lists: remove_perm(user_or_group=project.can_view_group, perm=CAN_VIEW, obj=locus_list) xbrowse_gene_list = find_matching_xbrowse_model(locus_list) if xbrowse_project and xbrowse_gene_list: BaseProjectGeneList.objects.filter(project=xbrowse_project, gene_list=xbrowse_gene_list).delete() return create_json_response({ 'locusListGuids': [locus_list['locusListGuid'] for locus_list in get_sorted_project_locus_lists(project, request.user)], })
def delete_project_locus_lists(request, project_guid): project = get_project_and_check_permissions(project_guid, request.user, CAN_EDIT) xbrowse_project = find_matching_xbrowse_model(project) request_json = json.loads(request.body) locus_lists = LocusList.objects.filter(guid__in=request_json['locusListGuids']) for locus_list in locus_lists: remove_perm(user_or_group=project.can_view_group, perm=CAN_VIEW, obj=locus_list) xbrowse_gene_list = find_matching_xbrowse_model(locus_list) if xbrowse_project and xbrowse_gene_list: BaseProjectGeneList.objects.filter(project=xbrowse_project, gene_list=xbrowse_gene_list).delete() return create_json_response({ 'locusListGuids': [locus_list['locusListGuid'] for locus_list in get_sorted_project_locus_lists(project, request.user)], })
def _can_edit_entity_id(project, entity_id_key, entity_id): base_project = find_matching_xbrowse_model(project) if base_project.vcffile_set.count() and not base_project.has_elasticsearch_index(): raise ValueError('Editing {} is disabled for projects which still use the mongo datastore'.format(entity_id_key)) if project.is_mme_enabled: filter_key = 'family__family_id' if entity_id_key == 'family_id' else 'individual_id' individual_filter = {'family__project': project, filter_key: entity_id} if any(indiv for indiv in Individual.objects.filter(**individual_filter) if indiv.mme_submitted_date and not indiv.mme_deleted_date): raise ValueError('Editing {} is disabled for {} because it has matchmaker submissions'.format( entity_id_key, entity_id))
def _save_pedigree_image_file(family, png_file_path): with open(png_file_path) as pedigree_image_file: family.pedigree_image.save(os.path.basename(png_file_path), File(pedigree_image_file)) family.save() # update deprecated model base_family = find_matching_xbrowse_model(family) if base_family: with open(png_file_path) as pedigree_image_file: base_family.pedigree_image.save(os.path.basename(png_file_path), File(pedigree_image_file)) base_family.save()
def _can_edit_entity_id(project, entity_id_key, entity_id): base_project = find_matching_xbrowse_model(project) if not base_project.has_elasticsearch_index(): raise ValueError( 'Editing {} is disabled for projects which still use the mongo datastore' .format(entity_id_key)) if project.is_mme_enabled and SEQR_ID_TO_MME_ID_MAP.find( { 'project_id': project.deprecated_project_id, entity_id_key: entity_id }).count() > 0: raise ValueError( 'Editing {} is disabled for {} because it has matchmaker submissions' .format(entity_id_key, entity_id))
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 _can_edit_entity_id(project, entity_id_key, entity_id): base_project = find_matching_xbrowse_model(project) if base_project.vcffile_set.count( ) and not base_project.has_elasticsearch_index(): raise ValueError( 'Editing {} is disabled for projects which still use the mongo datastore' .format(entity_id_key)) if project.is_mme_enabled: filter_key = 'family__family_id' if entity_id_key == 'family_id' else 'individual_id' individual_filter = {'family__project': project, filter_key: entity_id} if any(indiv for indiv in Individual.objects.filter(**individual_filter) if indiv.mme_submitted_date and not indiv.mme_deleted_date): raise ValueError( 'Editing {} is disabled for {} because it has matchmaker submissions' .format(entity_id_key, entity_id))
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 update_individual_alignment_sample(request, individual_guid): """Create or update samples for the given dataset Args: request: Django request object individual_guid (string): GUID of the individual that should be updated HTTP POST Request body - should contain the following json structure: { 'sampleType': <"WGS", "WES", or "RNA"> (required) 'datasetType': <"VARIANTS", or "ALIGN"> (required) 'elasticsearchIndex': <String> 'datasetPath': <String> 'datasetName': <String> 'ignoreExtraSamplesInCallset': <Boolean> 'mappingFile': { 'uploadedFileId': <Id for temporary uploaded file> } } Response body - will contain the following structure: """ individual = Individual.objects.get(guid=individual_guid) project = individual.family.project check_permissions(project, request.user, CAN_EDIT) request_json = json.loads(request.body) try: required_fields = ['sampleType', 'datasetFilePath'] if any(field not in request_json for field in required_fields): raise ValueError( "request must contain fields: {}".format(', '.join(required_fields))) sample_type = request_json['sampleType'] if sample_type not in {choice[0] for choice in Sample.SAMPLE_TYPE_CHOICES}: raise Exception("Sample type not supported: {}".format(sample_type)) dataset_path = request_json['datasetFilePath'] if not (dataset_path.endswith(".bam") or dataset_path.endswith(".cram")): raise Exception('BAM / CRAM file "{}" must have a .bam or .cram extension'.format(dataset_path)) validate_alignment_dataset_path(dataset_path) sample, created = Sample.objects.get_or_create( individual=individual, dataset_type=Sample.DATASET_TYPE_READ_ALIGNMENTS, is_active=True, ) sample.dataset_file_path = dataset_path sample.sample_type = sample_type sample.sample_id = dataset_path.split('/')[-1].split('.')[0] if created: sample.loaded_date = timezone.now() sample.save() # Deprecated update VCFFile records base_indiv = find_matching_xbrowse_model(individual) if base_indiv: base_indiv.bam_file_path = dataset_path base_indiv.save() response = { 'samplesByGuid': { sample.guid: get_json_for_sample(sample, individual_guid=individual_guid, project_guid=project.guid)} } if created: response['individualsByGuid'] = { individual.guid: {'sampleGuids': [s.guid for s in individual.sample_set.all()]} } return create_json_response(response) except Exception as e: return create_json_response({}, status=400, reason=e.message or str(e))
def _can_edit_entity_id(project, entity_id_key): base_project = find_matching_xbrowse_model(project) if base_project.vcffile_set.count() and not base_project.has_elasticsearch_index(): raise ValueError('Editing {} is disabled for projects which still use the mongo datastore'.format(entity_id_key))
def handle(self, *args, **options): from_project = Project.objects.get(guid=options['from_project']) to_project = Project.objects.get(guid=options['to_project']) to_base_project = find_matching_xbrowse_model(to_project) family_ids = options['family_ids'] families = Family.objects.filter(project=from_project, family_id__in=family_ids) print('Found {} out of {} families. No match for: {}.'.format( len(families), len(set(family_ids)), set(family_ids) - set([f.family_id for f in families]))) for f in families: print("==> Moving {}".format(f)) for seqr_individual in f.individual_set.all(): base_individual = find_matching_xbrowse_model(seqr_individual) base_individual.project = to_base_project base_individual.save() # Update individuals in phenotips if _phenotips_patient_exists(seqr_individual): # make sure phenotips_patient_id is up to date data_json = _get_patient_data( from_project, seqr_individual, ) seqr_individual.phenotips_patient_id = data_json["id"] seqr_individual.save() # update permissions phenotips_readonly_username, _ = _get_phenotips_uname_and_pwd_for_project( to_project.phenotips_user_id, read_only=True) _add_user_to_patient(phenotips_readonly_username, seqr_individual.phenotips_patient_id, allow_edit=False) phenotips_readwrite_username, _ = _get_phenotips_uname_and_pwd_for_project( to_project.phenotips_user_id, read_only=False) _add_user_to_patient(phenotips_readwrite_username, seqr_individual.phenotips_patient_id, allow_edit=True) # Update individuals samples/ VCFs for from_vcf_file in base_individual.vcf_files.all(): to_vcf_file, _ = VCFFile.objects.get_or_create( project=to_base_project, elasticsearch_index=from_vcf_file.elasticsearch_index, file_path=from_vcf_file.file_path, dataset_type=from_vcf_file.dataset_type, sample_type=from_vcf_file.sample_type, loaded_date=from_vcf_file.loaded_date, ) base_individual.vcf_files.add(to_vcf_file) base_individual.vcf_files.remove(from_vcf_file) # Update variant tags/ notes saved_variants = SavedVariant.objects.filter(family=f) for variant_tag in VariantTag.objects.filter( saved_variant__in=saved_variants).select_related( 'variant_tag_type'): if variant_tag.variant_tag_type.project: to_tag_type, created = get_or_create_seqr_model( VariantTagType, project=to_project, name=variant_tag.variant_tag_type.name) if created: update_seqr_model( to_tag_type, category=variant_tag.variant_tag_type.category, description=variant_tag.variant_tag_type. description, color=variant_tag.variant_tag_type.color, order=variant_tag.variant_tag_type.order, ) update_seqr_model(variant_tag, variant_tag_type=to_tag_type) else: to_project_tag, created = ProjectTag.objects.get_or_create( project=to_base_project, tag=variant_tag.variant_tag_type.name) if created: to_project_tag.category = variant_tag.variant_tag_type.category to_project_tag.title = variant_tag.variant_tag_type.description to_project_tag.color = variant_tag.variant_tag_type.color to_project_tag.order = variant_tag.variant_tag_type.order to_project_tag.save() variant_tag.project_tag = to_project_tag variant_tag.save() base_family = find_matching_xbrowse_model(f) for note in BaseVariantNote.objects.filter(family=base_family): note.project = to_base_project note.save() # Update families update_seqr_model(f, project=to_project) print("Done.")
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 add_alignment_dataset_handler(request, project_guid): """Create or update samples for the given dataset Args: request: Django request object project_guid (string): GUID of the project that should be updated HTTP POST Request body - should contain the following json structure: { 'sampleType': <"WGS", "WES", or "RNA"> (required) 'datasetType': <"VARIANTS", or "ALIGN"> (required) 'elasticsearchIndex': <String> 'datasetPath': <String> 'datasetName': <String> 'ignoreExtraSamplesInCallset': <Boolean> 'mappingFile': { 'uploadedFileId': <Id for temporary uploaded file> } } Response body - will contain the following structure: """ project = get_project_and_check_permissions(project_guid, request.user, permission_level=CAN_EDIT) request_json = json.loads(request.body) try: required_fields = ['sampleType', 'mappingFile'] if any(field not in request_json for field in required_fields): raise ValueError("request must contain fields: {}".format( ', '.join(required_fields))) sample_type = request_json['sampleType'] if sample_type not in { choice[0] for choice in Sample.SAMPLE_TYPE_CHOICES }: raise Exception( "Sample type not supported: {}".format(sample_type)) mapping_file_id = request_json['mappingFile']['uploadedFileId'] sample_id_to_individual_id_mapping = {} sample_dataset_path_mapping = {} for individual_id, dataset_path in load_uploaded_mapping_file( mapping_file_id).items(): if not (dataset_path.endswith(".bam") or dataset_path.endswith(".cram")): raise Exception( 'BAM / CRAM file "{}" must have a .bam or .cram extension'. format(dataset_path)) validate_alignment_dataset_path(dataset_path) sample_id = dataset_path.split('/')[-1].split('.')[0] sample_id_to_individual_id_mapping[sample_id] = individual_id sample_dataset_path_mapping[sample_id] = dataset_path matched_sample_id_to_sample_record = match_sample_ids_to_sample_records( project=project, sample_ids=sample_id_to_individual_id_mapping.keys(), sample_type=sample_type, dataset_type=Sample.DATASET_TYPE_READ_ALIGNMENTS, sample_id_to_individual_id_mapping= sample_id_to_individual_id_mapping, ) unmatched_samples = set( sample_id_to_individual_id_mapping.keys()) - set( matched_sample_id_to_sample_record.keys()) if len(unmatched_samples) > 0: raise Exception( 'The following Individual IDs do not exist: {}'.format( ", ".join(unmatched_samples))) _update_samples( matched_sample_id_to_sample_record, sample_dataset_path_mapping=sample_dataset_path_mapping) except Exception as e: traceback.print_exc() return create_json_response({'errors': [e.message or str(e)]}, status=400) if not matched_sample_id_to_sample_record: return create_json_response({'samplesByGuid': {}}) # Deprecated update VCFFile records for sample in matched_sample_id_to_sample_record.values(): base_indiv = find_matching_xbrowse_model(sample.individual) if base_indiv: base_indiv.bam_file_path = sample.dataset_file_path base_indiv.save() return create_json_response( _get_samples_json(matched_sample_id_to_sample_record, project_guid))