def _generate_slack_notification_for_seqr_match(individual, results): """ Generate a SLACK notifcation to say that a match happened initiated from a seqr user. """ matches = [] hpo_terms_by_id, genes_by_id, _ = get_mme_genes_phenotypes(results) for result in results: patient = result['patient'] gene_message = '' if patient.get('genomicFeatures'): gene_symbols = set() for gene in patient['genomicFeatures']: gene_symbol = gene['gene']['id'] if gene_symbol.startswith('ENSG'): gene_symbol = genes_by_id.get(gene_symbol, {}).get( 'geneSymbol', gene_symbol) gene_symbols.add(gene_symbol) gene_message = ' with genes {}'.format(' '.join( sorted(gene_symbols))) phenotypes_message = '' if patient.get('features'): phenotypes_message = ' with phenotypes {}'.format(' '.join([ '{} ({})'.format(feature['id'], hpo_terms_by_id.get(feature['id'])) for feature in patient['features'] ])) matches.append( ' - From {contact} at institution {institution}{gene_message}{phenotypes_message}.' .format( contact=patient['contact'].get('name', '(none given)'), institution=patient['contact'].get('institution', '(none given)'), gene_message=gene_message, phenotypes_message=phenotypes_message, )) message = u""" A search from a seqr user from project {project} individual {individual_id} had the following new match(es): {matches} {host}/{project_guid}/family_page/{family_guid}/matchmaker_exchange """.format( project=individual.family.project.name, individual_id=individual.individual_id, matches='\n\n'.join(matches), host=SEQR_HOSTNAME_FOR_SLACK_POST, project_guid=individual.family.project.guid, family_guid=individual.family.guid, ) post_to_slack(MME_SLACK_SEQR_MATCH_NOTIFICATION_CHANNEL, message)
def _generate_notification_for_seqr_match(submission, results): """ Generate a notifcation to say that a match happened initiated from a seqr user. """ matches = [] hpo_terms_by_id, genes_by_id, _ = get_mme_genes_phenotypes_for_results(results) for result in results: patient = result['patient'] gene_message = '' if patient.get('genomicFeatures'): gene_symbols = set() for gene in patient['genomicFeatures']: gene_symbol = gene['gene']['id'] if gene_symbol.startswith('ENSG'): gene_symbol = genes_by_id.get(gene_symbol, {}).get('geneSymbol', gene_symbol) gene_symbols.add(gene_symbol) gene_message = ' with genes {}'.format(' '.join(sorted(gene_symbols))) phenotypes_message = '' if patient.get('features'): phenotypes_message = ' with phenotypes {}'.format(' '.join( ['{} ({})'.format(feature['id'], hpo_terms_by_id.get(feature['id'])) for feature in patient['features']] )) matches.append(' - From {contact} at institution {institution}{gene_message}{phenotypes_message}.'.format( contact=patient['contact'].get('name', '(none given)'), institution=patient['contact'].get('institution', '(none given)'), gene_message=gene_message, phenotypes_message=phenotypes_message, )) individual = submission.individual project = individual.family.project message = u""" A search from a seqr user from project {project} individual {individual_id} had the following new match(es): {matches} {host}project/{project_guid}/family_page/{family_guid}/matchmaker_exchange """.format( project=project.name, individual_id=individual.individual_id, matches='\n\n'.join(matches), host=BASE_URL, project_guid=project.guid, family_guid=submission.individual.family.guid, ) post_to_slack(MME_SLACK_SEQR_MATCH_NOTIFICATION_CHANNEL, message) emails = map(lambda s: s.strip().split('mailto:')[-1], submission.contact_href.split(',')) email_message = EmailMessage( subject=u'New matches found for MME submission {} (project: {})'.format(individual.individual_id, project.name), body=message, to=[email for email in emails if email != MME_DEFAULT_CONTACT_EMAIL], from_email=MME_DEFAULT_CONTACT_EMAIL, ) email_message.send()
def _search_external_matches(nodes_to_query, patient_data): body = {'_disclaimer': MME_DISCLAIMER} body.update(patient_data) external_results = [] submission_gene_ids = set() for feature in patient_data['patient'].get('genomicFeatures', []): submission_gene_ids.update(get_gene_ids_for_feature(feature, {})) for node in nodes_to_query: headers = { 'X-Auth-Token': node['token'], 'Accept': MME_ACCEPT_HEADER, 'Content-Type': MME_ACCEPT_HEADER, 'Content-Language': 'en-US', } try: external_result = requests.post(url=node['url'], headers=headers, data=json.dumps(body)) if external_result.status_code != 200: try: message = external_result.json().get('message') except Exception: message = external_result.content error_message = '{} ({})'.format(message or 'Error', external_result.status_code) raise Exception(error_message) node_results = external_result.json()['results'] logger.info('Found {} matches from {}'.format( len(node_results), node['name'])) if node_results: _, _, gene_symbols_to_ids = get_mme_genes_phenotypes_for_results( node_results) invalid_results = [] for result in node_results: if (not submission_gene_ids) or \ _is_valid_external_match(result, submission_gene_ids, gene_symbols_to_ids): external_results.append(result) else: invalid_results.append(result) if invalid_results: error_message = 'Received {} invalid matches from {}'.format( len(invalid_results), node['name']) logger.error(error_message) except Exception as e: error_message = 'Error searching in {}: {}\n(Patient info: {})'.format( node['name'], e.message, json.dumps(patient_data)) logger.error(error_message) post_to_slack(MME_SLACK_ALERT_NOTIFICATION_CHANNEL, error_message) return external_results
def _generate_notification_for_incoming_match(results, incoming_query, incoming_request_node, incoming_patient): """ Generate a SLACK notifcation to say that a VALID match request came in and the following results were sent back. If Slack is not supported, a message is not sent, but details persisted. Args: response_from_matchbox (python requests object): contains the response from matchbox incoming_request (Django request object): The request that came into the view incoming_patient (JSON): The query patient JSON structure from outside MME node that was matched with """ incoming_patient_id = incoming_patient['patient']['id'] logger.info('{} MME matches found for patient {} from {}'.format( len(results), incoming_patient_id, incoming_request_node)) institution = incoming_patient['patient']['contact'].get( 'institution', incoming_request_node) contact_href = incoming_patient['patient']['contact'].get( 'href', '(sorry I was not able to read the information given for URL)') if not results: message_template = """A match request for {patient_id} came in from {institution} today. The contact information given was: {contact}. We didn't find any individuals in matchbox that matched that query well, *so no results were sent back*.""" post_to_slack( MME_SLACK_MATCH_NOTIFICATION_CHANNEL, message_template.format(institution=institution, patient_id=incoming_patient_id, contact=contact_href)) return new_matched_results = MatchmakerResult.objects.filter( originating_query=incoming_query).prefetch_related('submission') if not new_matched_results: message_template = """A match request for {patient_id} came in from {institution} today. The contact information given was: {contact}. We found {existing_results} existing matching individuals but no new ones, *so no results were sent back*.""" post_to_slack( MME_SLACK_MATCH_NOTIFICATION_CHANNEL, message_template.format(institution=institution, patient_id=incoming_patient_id, contact=contact_href, existing_results=len(results))) return hpo_terms_by_id, genes_by_id, _ = get_mme_genes_phenotypes_for_results( [incoming_patient]) match_results = [] all_emails = set() for result in new_matched_results: submission = result.submission individual = submission.individual project = individual.family.project result_text = u"""seqr ID {individual_id} from project {project_name} in family {family_id} inserted into matchbox on {insertion_date}, with seqr link {host}project/{project_guid}/family_page/{family_guid}/matchmaker_exchange""".replace( '\n', ' ').format( individual_id=individual.individual_id, project_guid=project.guid, project_name=project.name, family_guid=individual.family.guid, family_id=individual.family.family_id, insertion_date=submission.created_date.strftime('%b %d, %Y'), host=BASE_URL) emails = [ email.strip() for email in submission.contact_href.replace( 'mailto:', '').split(',') if email.strip() != MME_DEFAULT_CONTACT_EMAIL ] all_emails.update(emails) match_results.append((result_text, emails)) match_results = sorted(match_results, key=lambda result_tuple: result_tuple[0]) base_message = u"""Dear collaborators, matchbox found a match between a patient from {query_institution} and the following {number_of_results} case(s) in matchbox. The following information was included with the query, genes: {incoming_query_genes} phenotypes: {incoming_query_phenotypes} contact: {incoming_query_contact_name} email: {incoming_query_contact_url} We sent back the following: """.format( query_institution=institution, number_of_results=len(results), incoming_query_genes=', '.join( sorted([gene['geneSymbol'] for gene in genes_by_id.values()])), incoming_query_phenotypes=', '.join([ '{} ({})'.format(hpo_id, term) for hpo_id, term in hpo_terms_by_id.items() ]), incoming_query_contact_url=contact_href, incoming_query_contact_name=incoming_patient['patient']['contact'].get( 'name', '(sorry I was not able to read the information given for name'), ) message_template = u"""{base_message}{match_results} We sent this email alert to: {email_addresses_alert_sent_to}\n{footer}.""" post_to_slack( MME_SLACK_MATCH_NOTIFICATION_CHANNEL, message_template.format( base_message=base_message, match_results='\n'.join([text for text, _ in match_results]), email_addresses_alert_sent_to=', '.join(sorted(all_emails)), footer=MME_EMAIL_FOOTER)) for result_text, emails in match_results: email_message = EmailMessage( subject='Received new MME match', body=message_template.format( base_message=base_message, match_results=result_text, email_addresses_alert_sent_to=', '.join(emails), footer=MME_EMAIL_FOOTER), to=emails, from_email=MME_DEFAULT_CONTACT_EMAIL, ) email_message.send()
def _generate_notification_for_incoming_match(response_from_matchbox, incoming_request, incoming_patient): """ Generate a SLACK notifcation to say that a VALID match request came in and the following results were sent back. If Slack is not supported, a message is not sent, but details persisted. Args: response_from_matchbox (python requests object): contains the response from matchbox incoming_request (Django request object): The request that came into the view incoming_patient (JSON): The query patient JSON structure from outside MME node that was matched with """ results_from_matchbox = json.loads( response_from_matchbox.content)['results'] incoming_patient = json.loads(incoming_patient.strip()) incoming_patient_id = incoming_patient['patient']['id'] logger.info('{} MME matches found for patient {} from {}'.format( len(results_from_matchbox), incoming_patient_id, incoming_request.get_host())) institution = incoming_patient['patient']['contact'].get( 'institution', '(institution name not given)') contact_href = incoming_patient['patient']['contact'].get( 'href', '(sorry I was not able to read the information given for URL)') if len(results_from_matchbox) > 0: hpo_terms_by_id, genes_by_id, _ = get_mme_genes_phenotypes( [incoming_patient]) match_results = [] emails = set() for result in results_from_matchbox: individual = Individual.objects.filter( mme_submitted_data__patient__id=result['patient'] ['id']).first() project = individual.family.project result_text = u'seqr ID {individual_id} from project {project_name} in family {family_id} ' \ u'inserted into matchbox on {insertion_date}, with seqr link ' \ u'{host}project/{project_guid}/family_page/{family_guid}/matchmaker_exchange'.format( individual_id=individual.individual_id, project_guid=project.guid, project_name=project.name, family_guid=individual.family.guid, family_id=individual.family.family_id, insertion_date=individual.mme_submitted_date.strftime('%b %d, %Y'), host=BASE_URL) match_results.append(result_text) emails.update([ i.strip() for i in project.mme_contact_url.replace( 'mailto:', '').split(',') ]) emails = [ email for email in emails if email != MME_DEFAULT_CONTACT_EMAIL ] message = u"""Dear collaborators, matchbox found a match between a patient from {query_institution} and the following {number_of_results} case(s) in matchbox. The following information was included with the query, genes: {incoming_query_genes} phenotypes: {incoming_query_phenotypes} contact: {incoming_query_contact_name} email: {incoming_query_contact_url} We sent back: {match_results} We sent this email alert to: {email_addresses_alert_sent_to} Thank you for using the matchbox system for the Matchmaker Exchange at the Broad Center for Mendelian Genomics. Our website can be found at https://seqr.broadinstitute.org/matchmaker/matchbox and our legal disclaimers can be found found at https://seqr.broadinstitute.org/matchmaker/disclaimer.""".format( query_institution=institution, number_of_results=len(results_from_matchbox), incoming_query_genes=', '.join( sorted([gene['geneSymbol'] for gene in genes_by_id.values()])), incoming_query_phenotypes=', '.join([ '{} ({})'.format(hpo_id, term) for hpo_id, term in hpo_terms_by_id.items() ]), incoming_query_contact_url=contact_href, incoming_query_contact_name=incoming_patient['patient'] ['contact'].get( 'name', '(sorry I was not able to read the information given for name' ), match_results='\n'.join(match_results), email_addresses_alert_sent_to=', '.join(emails), ) post_to_slack(MME_SLACK_MATCH_NOTIFICATION_CHANNEL, message) # TODO re-enable MME email # email_message = EmailMessage( # subject='Received new MME match', # body=message, # to=emails, # from_email=MME_DEFAULT_CONTACT_EMAIL, # ) # email_message.send() else: message = """Dear collaborators, This match request came in from {institution} today ({today}). The contact information given was: {contact}. We didn't find any individuals in matchbox that matched that query well, *so no results were sent back*. """.format(institution=institution, today=datetime.now().strftime('%b %d, %Y'), contact=contact_href) post_to_slack(MME_SLACK_EVENT_NOTIFICATION_CHANNEL, message)