Beispiel #1
0
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)
Beispiel #2
0
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()
Beispiel #3
0
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
Beispiel #4
0
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()
Beispiel #5
0
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)