diff --git a/gracedb/alert.py b/gracedb/alert.py index 846a248aab89745e6f6d2c1ea2054085718b6da2..101f0f0a98594a55969db1976e1ffa9c158cc84e 100644 --- a/gracedb/alert.py +++ b/gracedb/alert.py @@ -4,6 +4,7 @@ from subprocess import Popen, PIPE, STDOUT from django.core.mail import EmailMessage from django.conf import settings +from django.contrib.auth.models import Group import json @@ -31,6 +32,79 @@ def get_twilio_from(): return from_.phone_number raise RuntimeError('Could not determine "from" Twilio phone number') +def make_twilio_calls(event, twilio_recips, alert_type, **kwargs): + """ + USAGE: + ------ + New event created: + make_twilio_calls(event, twilio_recips, "create") + New label applied to event (Label is a GraceDB model): + make_twilio_calls(event, twilio_recips, "label", label=Label) + + Note: twilio_recips is a list of users - we need phone numbers + and group memberships for permission checks. + """ + + if (alert_type == "create"): + # twiml_base_url is the URL of a TwiML Bin + # (https://support.twilio.com/hc/en-us/articles/230878368) + # with the following content: + # + # <?xml version="1.0" encoding="UTF-8"?> + # <Response> + # <Say> + # A {{pipeline}} event with Grace DB ID {{graceid}} was created. + # </Say> + # <Sms> + # A {{pipeline}} event with GraceDB ID {{graceid}} was created. + # https://gracedb-test.ligo.org/events/view/{{graceid}} + # </Sms> + # </Response> + twiml_base_url = 'https://handler.twilio.com/twiml/' + settings.TWILIO_CREATE_KEY + twiml_url = '{0}?pipeline={1}&graceid={2}'.format( + twiml_base_url, event.pipeline.name, event.graceid()) + elif (alert_type == "label"): + # twiml_base_url is the URL of a TwiML Bin + # (https://support.twilio.com/hc/en-us/articles/230878368) + # with the following content: + # + # <?xml version="1.0" encoding="UTF-8"?> + # <Response> + # <Say> + # A {{pipeline}} event with Grace DB ID {{graceid}} was labelled with {{label_lower}}. + # </Say> + # <Sms> + # A {{pipeline}} event with GraceDB ID {{graceid}} was labelled with {{label}} + # https://gracedb-test.ligo.org/events/view/{{graceid}} + # </Sms> + # </Response> + twiml_base_url = 'https://handler.twilio.com/twiml/' + settings.TWILIO_LABEL_KEY + label = kwargs['label'] + twiml_url = '{0}?pipeline={1}&graceid={2}&label={3}&label_lower={4}'.format( + twiml_base_url, event.pipeline.name, event.graceid(), label.name, label.name.lower()) + else: + log.exception('Failed to process alert_type in make_twilio_calls') + + # Get "from" phone number. + from_ = get_twilio_from() + + # Get LVC user group for checks made below. + lvc_group = Group.objects.get(name=settings.LVC_GROUP) + + # Loop over recipients and make calls. + for recip in twilio_recips: + try: + # Only make calls to LVC members. Non-LVC members shouldn't + # even be able to sign up with a phone number, but this is another + # safety measure. + if lvc_group in recip.user.groups.all(): + log.info('calling %s', recip.user.username) + twilio_client.calls.create(recip.phone, from_, twiml_url, method='GET') + else: + log.info('user %s is not an LVC member, call not made' % recip.user.username) + except: + log.exception('Failed to create call') + def issueAlert(event, location, event_url, serialized_object=None): issueXMPPAlert(event, location, serialized_object=serialized_object) issueEmailAlert(event, event_url) @@ -87,7 +161,7 @@ def issueAlertForLabel(event, label, doxmpp, serialized_event=None, event_url=No if recip.email: profileRecips.append(recip.email) if recip.phone: - phoneRecips.append(recip.phone) + phoneRecips.append(recip) if event.search: subject = "[gracedb] %s / %s / %s / %s" % (label.name, event.pipeline.name, event.search.name, event.graceid()) @@ -115,35 +189,8 @@ def issueAlertForLabel(event, label, doxmpp, serialized_event=None, event_url=No email = EmailMessage(subject, message, fromaddress, toaddresses, bccaddresses) email.send() - # twiml_base_url is the URL of a TwiML Bin - # (https://support.twilio.com/hc/en-us/articles/230878368) - # with the following content: - # - # <?xml version="1.0" encoding="UTF-8"?> - # <Response> - # <Say> - # A {{pipeline}} event with Grace DB ID {{graceid}} was labelled with {{label_lower}}. - # </Say> - # <Sms> - # A {{pipeline}} event with GraceDB ID {{graceid}} was labelled with {{label}} - # https://gracedb-test.ligo.org/events/view/{{graceid}} - # </Sms> - # </Response> - twiml_base_url = 'https://handler.twilio.com/twiml/EH7a2cef360c90eec301c3bf325ce1790a' - - twiml_url = '{0}?pipeline={1}&graceid={2}&label={3}&label_lower={4}'.format( - twiml_base_url, event.pipeline.name, event.graceid(), label.name, label.name.lower()) - log.info('phoneRecips: %s' % phoneRecips) - from_ = get_twilio_from() - log.info('from_: %s' % from_) - for recip in phoneRecips: - log.info('in for loop') - try: - log.info('issueAlertForLabel: calling %s', recip) - twilio_client.calls.create(recip, from_, twiml_url, method='GET') - except: - log.exception('Failed to create call') - + # Make phone calls. + make_twilio_calls(event, phoneRecips, "label", label=label) def issueEmailAlert(event, event_url): @@ -177,13 +224,13 @@ def issueEmailAlert(event, event_url): if recip.email: bccaddresses.append(recip.email) if recip.phone: - twilio_recips.append(recip.phone) + twilio_recips.append(recip) else: if event.far and event.far < trigger.farThresh: if recip.email: bccaddresses.append(recip.email) if recip.phone: - twilio_recips.append(recip.phone) + twilio_recips.append(recip) subject = "[gracedb] %s event. ID: %s" % (event.pipeline.name, event.graceid()) message = """ New Event @@ -207,33 +254,8 @@ Event Summary: email = EmailMessage(subject, message, fromaddress, toaddresses, bccaddresses) email.send() - #send_mail(subject, message, fromaddress, toaddresses) - - # twiml_base_url is the URL of a TwiML Bin - # (https://support.twilio.com/hc/en-us/articles/230878368) - # with the following content: - # - # <?xml version="1.0" encoding="UTF-8"?> - # <Response> - # <Say> - # A {{pipeline}} event with Grace DB ID {{graceid}} was created. - # </Say> - # <Sms> - # A {{pipeline}} event with GraceDB ID {{graceid}} was created. - # https://gracedb-test.ligo.org/events/view/{{graceid}} - # </Sms> - # </Response> - twiml_base_url = 'https://handler.twilio.com/twiml/EHe8ac043be47528c50558954791fb11fe' - - twiml_url = '{0}?pipeline={1}&graceid={2}'.format( - twiml_base_url, event.pipeline.name, event.graceid()) - from_ = get_twilio_from() - for recip in twilio_recips: - try: - log.info('issueEmailAlert: calling %s', recip) - twilio_client.calls.create(recip, from_, twiml_url, method='GET') - except: - log.exception('Failed to create call') + # Make phone calls. + make_twilio_calls(event, twilio_recips, "create") def issueXMPPAlert(event, location, alert_type="new", description="", serialized_object=None): diff --git a/userprofile/forms.py b/userprofile/forms.py index a6f8a3209a4bc8852b2e268f2efddaff9af33d37..9d092e5f8dbdf8b324fc6b62f86dd016940976a5 100644 --- a/userprofile/forms.py +++ b/userprofile/forms.py @@ -46,5 +46,7 @@ class TriggerForm(forms.ModelForm): class ContactForm(forms.ModelForm): class Meta: model = Contact - exclude = ['user'] - + fields = ['desc','email','phone'] + help_texts = { + 'phone': 'Prototype service: may not be available in the future.' + } diff --git a/userprofile/migrations/0004_add_contact_phone_number.py b/userprofile/migrations/0004_add_contact_phone_number.py new file mode 100644 index 0000000000000000000000000000000000000000..d262aa1aecfc40cbd90d6788ccfaead3a14d5b2c --- /dev/null +++ b/userprofile/migrations/0004_add_contact_phone_number.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import userprofile.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('userprofile', '0003_trigger_label_query'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='phone', + field=userprofile.models.PhoneNumberField(blank=True, max_length=255, validators=[userprofile.models.validate_phone, userprofile.models.validate_phone, userprofile.models.validate_phone]), + ), + migrations.AlterField( + model_name='contact', + name='email', + field=models.EmailField(max_length=254, blank=True), + ), + ]