Gitlab will migrate to a new storage backend starting 0300 UTC on 2020-04-04. We do not anticipate a maintenance window for this migration. Performance may be impacted over the weekend. Thanks for your patience.

Commit e5aa17a3 authored by Tanner Prestegard's avatar Tanner Prestegard Committed by GraceDB

Updates and bugfixes for phone and email alerts

parent 2b65fae7
......@@ -53,8 +53,8 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# TwiML bin SIDs (for Twilio)
'create': 'EH761b6a35102737e3d21830a484a98a08',
'label': 'EHb596a53b9c92a41950ce1a47335fd834',
'new': 'EH761b6a35102737e3d21830a484a98a08',
'label_added': 'EHb596a53b9c92a41950ce1a47335fd834',
'test': 'EH6c0a168b0c6b011047afa1caeb49b241',
from __future__ import absolute_import
import logging
from django.core.mail import EmailMessage
from django.conf import settings
from django.core.mail import EmailMessage
from django.urls import reverse
from core.time_utils import gpsToUtc
from core.urls import build_absolute_uri
# Set up logger
log = logging.getLogger(__name__)
logger = logging.getLogger(__name__)
EMAIL_SUBJECT_NEW = "[gracedb] {pipeline} event. ID: {graceid}"
New Event
{group} / {pipeline}
GRACEID: {graceid}
Info: {url}
Data: {file_url}
Submitter: {submitter}
Event Summary:
EMAIL_SUBJECT_LABEL = "[gracedb] {label} / {pipeline} / {search} / {graceid}"
EMAIL_SUBJECT_LABEL_NOSEARCH = "[gracedb] {label} / {pipeline} / {graceid}"
A {pipeline} event with graceid {graceid} was labeled with {label}: {url}
def indent(nindent, text):
return "\n".join([(nindent*' ')+line for line in text.split('\n')])
def prepareSummary(event):
gpstime = event.gpstime
utctime = gpsToUtc(gpstime).strftime("%Y-%m-%d %H:%M:%S")
......@@ -31,60 +52,47 @@ def prepareSummary(event):
Component masses: %.2f, %.2f """ % (si.mass1, si.mass2)
return summary
def issue_email_alerts(event, event_url):
# Check settings switch for turning off email alerts
if not settings.SEND_EMAIL_ALERTS:
def issue_email_alerts(event, recips, label=None):
# The right way of doing this is to make the email alerts filter-able
# by search. But this is a low priority dev task. For now, we simply
# short-circuit in case this is an MDC event.
if and == 'MDC':
# Prepare URLs for email message body
event_url = build_absolute_uri(reverse("view", args=[event.graceid]))
file_url = build_absolute_uri(reverse("file_list", args=[event.graceid]))
# Gather Recipients
if == 'Test':
fromaddress = settings.ALERT_TEST_EMAIL_FROM
toaddresses = settings.ALERT_TEST_EMAIL_TO
bccaddresses = []
# Compile subject and message content
if label is None:
# Alert for new event
subject = EMAIL_SUBJECT_NEW.format(,
message = EMAIL_MESSAGE_NEW.format(,, graceid=event.graceid,
url=event_url, file_url=file_url,
summary=indent(3, prepareSummary(event)))
fromaddress = settings.ALERT_EMAIL_FROM
toaddresses = settings.ALERT_EMAIL_TO
# XXX Bizarrely, this settings.ALERT_EMAIL_BCC seems to be overwritten in a
# persistent way between calls, so that you can get alerts going out to the
# wrong contacts. I find that it works if you just start with an empty list
# See:
#bccaddresses = settings.ALERT_EMAIL_BCC
bccaddresses = []
pipeline = event.pipeline
triggers = pipeline.trigger_set.filter(labels=None)
for trigger in triggers:
for recip in trigger.contacts.all():
if ((event.far and event.far < trigger.farThresh)
or not trigger.farThresh):
subject = "[gracedb] %s event. ID: %s" % (, event.graceid)
message = """
New Event
%s / %s
Info: %s
Data: %s
Submitter: %s
Event Summary:
message %= (,,
"%s %s" % (event.submitter.first_name, event.submitter.last_name),
indent(3, prepareSummary(event))
email = EmailMessage(subject, message, fromaddress, toaddresses, bccaddresses)
# Alert for label
subject = EMAIL_SUBJECT_LABEL.format(,,,
subject = EMAIL_SUBJECT_LABEL_NOSEARCH.format(,, graceid=event.graceid)
message = EMAIL_MESSAGE_LABEL.format(,
graceid=event.graceid,, url=event_url)
# Actual recipients should be BCC'd
bcc_addresses = [ for recip in recips]
# Compile from/to addresses
from_address = settings.ALERT_EMAIL_FROM
to_addresses = settings.ALERT_EMAIL_TO
# Log email recipients
logger.debug("Sending email to {recips}".format(
recips=", ".join(bcc_addresses)))
# Send email
email = EmailMessage(subject, message, from_address, to_addresses,
......@@ -66,6 +66,11 @@ class EventLabelAlertIssuer(AlertIssuerWithParentEvent):
serializer_class = staticmethod(labelToDict)
alert_types = ['label_added', 'label_removed']
def issue_alerts(self):
issue_alerts(self.get_parent_obj(), self.alert_type,
self.serialize_obj(), self.serialize_parent(),
class EventVOEventAlertIssuer(AlertIssuerWithParentEvent):
serializer_class = staticmethod(voeventToDict)
......@@ -39,7 +39,7 @@ def get_alert_recips(event_or_superevent):
# Filter on FAR threshold requirements
query = Q(farThresh__isnull=True)
if event.far:
query |= Q(farThresh__lt=event.far)
query |= Q(farThresh__gt=event.far)
triggers = triggers.filter(query)
# Contacts for all triggers, make sure user is in LVC group (safeguard)
contacts = Contact.objects.filter(trigger__in=triggers,
......@@ -52,8 +52,8 @@ def get_alert_recips(event_or_superevent):
def get_alert_recips_for_label(event_or_superevent, label):
# Blank QuerySets for recipients
email_recips = QuerySet()
phone_recips = QuerySet()
email_recips = Contact.objects.none()
phone_recips = Contact.objects.none()
# Construct a queryset containing only this object; needed for
# call to filter_for_labels
......@@ -97,7 +97,7 @@ def get_alert_recips_for_label(event_or_superevent, label):
def issue_alerts(event_or_superevent, alert_type, serialized_object,
serialized_parent=None, label=None):
# Send XMPP alert
if settings.SEND_XMPP_ALERTS:
......@@ -128,21 +128,14 @@ def issue_alerts(event_or_superevent, alert_type, serialized_object,
if event.offline:
# Compile phone and email recipients for new or label alerts
if alert_type not in ["new", "label"]:
if alert_type == "new":
email_recips, phone_recips = get_alert_recips(event_or_superevent)
# Force label = None for new alerts
label = None
elif alert_type == "label":
elif alert_type == "label_added":
email_recips, phone_recips = \
get_alert_recips_for_label(event_or_superevent, label)
if settings.SEND_EMAIL_ALERTS:
url = reverse('view', args=[event_or_superevent.graceid])
issue_email_alerts(event_or_superevent, url)
if settings.SEND_EMAIL_ALERTS and email_recips.exists():
issue_email_alerts(event_or_superevent, email_recips, label=label)
if settings.SEND_PHONE_ALERTS and phone_recips:
if settings.SEND_PHONE_ALERTS and phone_recips.exists():
issue_phone_alerts(event_or_superevent, phone_recips, label=label)
......@@ -3,7 +3,11 @@ import logging
import socket
from django.conf import settings
from django.urls import reverse
from django_twilio.client import twilio_client
from core.urls import build_absolute_uri
from events.permission_utils import is_external
# Set up logger
......@@ -20,13 +24,11 @@ TWIML_ARG_STR = {
# TODO: fix these by using reverse
# Dict for managing Twilio message contents.
'new': ('A {pipeline} event with GraceDB ID {graceid} was created.'
' https://{server}{graceid}'),
'new': 'A {pipeline} event with GraceDB ID {graceid} was created. {url}',
'label_added': ('A {pipeline} event with GraceDB ID {graceid} was labeled '
'with {label}. https://{server}{graceid}')
'with {label}. {url}'),
......@@ -55,9 +57,6 @@ def issue_phone_alerts(event, contacts, label=None):
alert_type = "new"
# Get server name.
hostname = socket.gethostname()
# Get "from" phone number.
from_ = get_twilio_from()
......@@ -65,7 +64,8 @@ def issue_phone_alerts(event, contacts, label=None):
msg_params = {
'graceid': event.graceid,
'server': hostname,
'server': settings.SERVER_HOSTNAME,
'url': build_absolute_uri(reverse('view', args=[event.graceid])),
if alert_type == "label_added":
msg_params['label'] =
......@@ -43,6 +43,11 @@ class SupereventLabelAlertIssuer(AlertIssuerWithParentSuperevent):
serializer_class = SupereventLabelSerializer
alert_types = ['label_added', 'label_removed']
def issue_alerts(self):
issue_alerts(self.get_parent_obj(), self.alert_type,
self.serialize_obj(), self.serialize_parent(),
class SupereventVOEventAlertIssuer(AlertIssuerWithParentSuperevent):
serializer_class = SupereventVOEventSerializer
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment