예제 #1
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()
예제 #2
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
예제 #3
0
def _parse_mme_results(submission, saved_results, user, additional_genes=None, response_json=None):
    results = []
    contact_institutions = set()
    prefetch_related_objects(saved_results, 'originating_submission__individual__family__project')
    for result_model in saved_results:
        result = result_model.result_data
        result['matchStatus'] = _get_json_for_model(result_model)
        if result_model.originating_submission:
            originating_family = result_model.originating_submission.individual.family
            if has_project_permissions(originating_family.project, user):
                result['originatingSubmission'] = {
                    'originatingSubmissionGuid': result_model.originating_submission.guid,
                    'familyGuid': originating_family.guid,
                    'projectGuid': originating_family.project.guid,
                }
        results.append(result)
        contact_institutions.add(result['patient']['contact'].get('institution', '').strip().lower())

    additional_hpo_ids = {feature['id'] for feature in (submission.features or []) if feature.get('id')}
    if not additional_genes:
        additional_genes = set()
    additional_genes.update({gene_feature['gene']['id'] for gene_feature in (submission.genomic_features or [])})

    hpo_terms_by_id, genes_by_id, gene_symbols_to_ids = get_mme_genes_phenotypes_for_results(
        results, additional_genes=additional_genes, additional_hpo_ids=additional_hpo_ids)

    parsed_results = [_parse_mme_result(res, hpo_terms_by_id, gene_symbols_to_ids, submission.guid) for res in results]
    parsed_results_gy_guid = {result['matchStatus']['matchmakerResultGuid']: result for result in parsed_results}

    contact_notes = {note.institution: _get_json_for_model(note, user=user)
                     for note in MatchmakerContactNotes.objects.filter(institution__in=contact_institutions)}

    submission_json = get_json_for_matchmaker_submission(
        submission, individual_guid=submission.individual.guid,
        additional_model_fields=['contact_name', 'contact_href', 'submission_id']
    )
    submission_json.update({
        'mmeResultGuids': list(parsed_results_gy_guid.keys()),
        'phenotypes': parse_mme_features(submission.features, hpo_terms_by_id),
        'geneVariants': parse_mme_gene_variants(submission.genomic_features, gene_symbols_to_ids),
    })

    response = {
        'mmeResultsByGuid': parsed_results_gy_guid,
        'mmeContactNotes': contact_notes,
        'mmeSubmissionsByGuid': {submission.guid: submission_json},
        'individualsByGuid': {submission.individual.guid: {'mmeSubmissionGuid': submission.guid}},
        'genesById': genes_by_id,
    }
    if response_json:
        response.update(response_json)
    return create_json_response(response)
예제 #4
0
파일: external_api.py 프로젝트: uwgsit/seqr
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()