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

Rename Trigger model to Notification

Also squash migrations in the alerts app.
parent d0ae91eb
......@@ -170,12 +170,12 @@ On the new server, as yourself, import the database using the ``gracedb`` user's
Note that files related to the events aren't part of the database and won't exist on the new server unless you copy them over, too (see :ref:`copying_event_data` for more information).
Next, become the ``gracedb`` user, enter the Django manager shell, and delete all Contacts and Triggers so that people don't get phone or email alerts from this instance without signing up for them::
Next, become the ``gracedb`` user, enter the Django manager shell, and delete all Contacts and Notifications so that people don't get phone or email alerts from this instance without signing up for them::
from userprofile.models import Contact, Trigger
for c in Contacts.objects.iterator():
from alerts.models import Contact, Notification
for c in Contact.objects.iterator():
c.delete()
for t in Trigger.objects.iterator():
for t in Notification.objects.iterator():
t.delete()
You might want to delete the Events, too, especially if you copy the production database.
......
......@@ -181,6 +181,6 @@ See :ref:`sql_tips` for how to do this.
A few things that you may want to do after copying the database, but before beginning your debugging:
* Turn off phone alerts! Obviously the Contact and Trigger instances are part of the database you just copied and will trigger and annoy people if you submit events for testing. The easiest solution is probably to just delete all of the Contact and/or Trigger objects (in the copied database) through the Django shell.
* Turn off phone alerts! Obviously the Contact and Notification instances are part of the database you just copied and will trigger and annoy people if you submit events for testing. The easiest solution is probably to just delete all of the Contact and/or Notification objects (in the copied database) through the Django shell.
* You may want to turn off XMPP alerts just to be safe.
from django.contrib import admin
from .models import Contact, Trigger
from .models import Contact, Notification
from django.contrib import admin
class ContactManager(admin.ModelAdmin):
pass
# list_display = [ 'user', 'desc' ]
class TriggerManager(admin.ModelAdmin):
class NotificationManager(admin.ModelAdmin):
pass
# exclude = [ 'labels' ]
# list_display = [ 'user', ]
admin.site.register(Contact, ContactManager)
admin.site.register(Trigger, TriggerManager)
admin.site.register(Notification, NotificationManager)
......@@ -5,7 +5,7 @@ from django.utils.html import conditional_escape
from django.forms.utils import ErrorList
from django.core.exceptions import NON_FIELD_ERRORS
from .models import Trigger, Contact
from .models import Notification, Contact
from search.query.labels import parseLabelQuery
from pyparsing import ParseException
......@@ -13,13 +13,13 @@ from collections import defaultdict
import logging
log = logging.getLogger(__name__)
def triggerFormFactory(postdata=None, user=None):
def notificationFormFactory(postdata=None, user=None):
class TF(forms.ModelForm):
farThresh = forms.FloatField(label='FAR Threshold (Hz)',
far_threshold = forms.FloatField(label='FAR Threshold (Hz)',
required=False)
class Meta:
model = Trigger
fields = ['contacts', 'pipelines', 'farThresh', 'labels', 'label_query']
model = Notification
fields = ['contacts', 'pipelines', 'far_threshold', 'labels', 'label_query']
widgets = {'label_query': forms.TextInput(attrs={'size': 50})}
help_texts = {
......
......@@ -34,15 +34,15 @@ def get_alert_recips(event_or_superevent):
pass
elif is_event(event_or_superevent):
event = event_or_superevent
# Queryset of all triggers for this pipeline
triggers = event.pipeline.trigger_set.filter(labels=None)
# Queryset of all notifications for this pipeline
notifications = event.pipeline.notification_set.filter(labels=None)
# Filter on FAR threshold requirements
query = Q(farThresh__isnull=True)
query = Q(far_threshold__isnull=True)
if 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,
query |= Q(far_threshold__gt=event.far)
notifications = notifications.filter(query)
# Contacts for all notifications, make sure user is in LVC group (safeguard)
contacts = Contact.objects.filter(notification__in=notifications,
user__groups__name=settings.LVC_GROUP).select_related('user')
email_recips = contacts.exclude(email="")
phone_recips = contacts.exclude(phone="")
......@@ -60,7 +60,7 @@ def get_alert_recips_for_label(event_or_superevent, label):
qs = event_or_superevent._meta.model.objects.filter(
pk=event_or_superevent.pk)
# Triggers on given label matching pipeline OR with no pipeline;
# Notifications on given label matching pipeline OR with no pipeline;
# no pipeline indicates that pipeline is irrelevant
if is_superevent(event_or_superevent):
# TODO: fix this
......@@ -69,26 +69,26 @@ def get_alert_recips_for_label(event_or_superevent, label):
event = event_or_superevent
query = Q(pipelines=event.pipeline) | Q(pipelines=None)
# Iterate over triggers found from the label query
# Iterate over notifications found from the label query
# TODO: this doesn't work quite correctly since negated labels aren't
# properly handled in the view function which creates triggers.
# Example: a trigger with '~INJ' as the label_query has INJ in its labels
# properly handled in the view function which creates notifications.
# Example: a notification with '~INJ' as the label_query has INJ in its labels
# Idea: have filter_for_labels return a Q object generated from the
# label query
triggers = label.trigger_set.filter(query).prefetch_related('contacts')
for trigger in triggers:
notifications = label.notification_set.filter(query).prefetch_related('contacts')
for notification in notifications:
if len(trigger.label_query) > 0:
qs_out = filter_for_labels(qs, trigger.label_query)
if len(notification.label_query) > 0:
qs_out = filter_for_labels(qs, notification.label_query)
# If the label query cleans out our query set, we'll continue
# without adding the recipient.
if not qs_out.exists():
continue
# Compile a list of recipients from the trigger's contacts.
# Compile a list of recipients from the notification's contacts.
# Require that the user is in the LVC group as a safeguard
contacts = trigger.contacts.filter(user__groups__name=
contacts = notification.contacts.filter(user__groups__name=
settings.LVC_GROUP)
email_recips |= contacts.exclude(email="").select_related('user')
phone_recips |= contacts.exclude(phone="").select_related('user')
......
......@@ -4,7 +4,7 @@ from django.conf import settings
from django.contrib.auth.models import Group
from django.core.management.base import BaseCommand, CommandError
from alerts.models import Contact, Trigger
from alerts.models import Contact, Notification
class Command(BaseCommand):
......@@ -18,19 +18,20 @@ class Command(BaseCommand):
verbose = not options['quiet']
if verbose:
self.stdout.write(('Checking inactive users\' triggers and '
self.stdout.write(('Checking inactive users\' notifications and '
'contacts at {0}').format(datetime.datetime.utcnow()))
# Get contacts and triggers whose user is no longer in the LVC
# Get contacts and notifications whose user is no longer in the LVC
lvc = Group.objects.get(name=settings.LVC_GROUP)
triggers = Trigger.objects.exclude(user__groups=lvc)
notifications = Notification.objects.exclude(user__groups=lvc)
contacts = Contact.objects.exclude(user__groups=lvc)
# Generate log message
if verbose:
if triggers.exists():
t_log_msg = "Deleting {0} triggers: ".format(triggers.count())\
+ " | ".join([t.__str__() for t in triggers])
if notifications.exists():
t_log_msg = "Deleting {0} notifications: ".format(
notifications.count()) + " | ".join([t.__str__()
for t in notifications])
self.stdout.write(t_log_msg)
if contacts.exists():
c_log_msg = "Deleting {0} contacts: ".format(contacts.count())\
......@@ -38,5 +39,5 @@ class Command(BaseCommand):
self.stdout.write(c_log_msg)
# Delete
triggers.delete()
notifications.delete()
contacts.delete()
# -*- coding: utf-8 -*-
# Generated by Django 1.11.18 on 2019-01-17 20:24
# Generated by Django 1.11.18 on 2019-01-17 20:40
from __future__ import unicode_literals
import alerts.fields
......@@ -31,11 +31,10 @@ class Migration(migrations.Migration):
],
),
migrations.CreateModel(
name='Trigger',
name='Notification',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('triggerType', models.CharField(blank=True, choices=[(b'create', b'create'), (b'change', b'change'), (b'label', b'label')], max_length=20)),
('farThresh', models.FloatField(blank=True, null=True)),
('far_threshold', models.FloatField(blank=True, null=True)),
('label_query', models.CharField(blank=True, max_length=100)),
('contacts', models.ManyToManyField(to='alerts.Contact')),
('labels', models.ManyToManyField(blank=True, to='events.Label')),
......
......@@ -61,16 +61,12 @@ class Contact(models.Model):
self.call_phone, self.text_phone))
class Trigger(models.Model):
# TP 6 Jul 2017: TYPES and triggerType don't seem to be used anywhere...
TYPES = ( ("create", "create"), ("change","change"), ("label","label") )
triggerType = models.CharField(max_length=20, choices=TYPES, blank=True)
class Notification(models.Model):
user = models.ForeignKey(UserModel, null=False)
labels = models.ManyToManyField(Label, blank=True)
pipelines = models.ManyToManyField(Pipeline, blank=True)
contacts = models.ManyToManyField(Contact, blank=False)
farThresh = models.FloatField(blank=True, null=True)
far_threshold = models.FloatField(blank=True, null=True)
label_query = models.CharField(max_length=100, blank=True)
def __unicode__(self):
......@@ -81,8 +77,8 @@ class Trigger(models.Model):
def userlessDisplay(self):
thresh = ""
if self.farThresh:
thresh = " & (far < %s)" % self.farThresh
if self.far_threshold:
thresh = " & (far < %s)" % self.far_threshold
if self.label_query:
label_disp = self.label_query
......
......@@ -5,7 +5,7 @@ from django.contrib.auth.models import Group as AuthGroup
from django.urls import reverse
from core.tests.utils import GraceDbTestBase
from alerts.models import Contact, Trigger
from alerts.models import Contact, Notification
class TestIndexView(GraceDbTestBase):
......@@ -192,16 +192,16 @@ class TestNotificationDeleteView(GraceDbTestBase):
def setUpTestData(cls):
super(TestNotificationDeleteView, cls).setUpTestData()
# Create a contact and a trigger (notification)
# Create a contact and a notification
cls.contact = Contact.objects.create(user=cls.internal_user,
desc='test contact', email='test@test.com')
cls.notification = Trigger.objects.create(user=cls.internal_user)
cls.notification = Notification.objects.create(user=cls.internal_user)
cls.notification.contacts.add(cls.contact)
# Create another contact and trigger (notification)
# Create another contact and notification
cls.other_contact = Contact.objects.create(user=cls.lvem_user,
desc='test contact', email='test@test.com')
cls.other_notification = Trigger.objects.create(user=cls.lvem_user)
cls.other_notification = Notification.objects.create(user=cls.lvem_user)
cls.other_notification.contacts.add(cls.other_contact)
def test_internal_user_delete(self):
......@@ -228,14 +228,14 @@ class TestNotificationDeleteView(GraceDbTestBase):
def test_lvem_user_delete(self):
"""LV-EM user can't delete notifications"""
for t in Trigger.objects.all():
for t in Notification.objects.all():
url = reverse('userprofile-delete', args=[t.id])
response = self.request_as_user(url, "GET", self.lvem_user)
self.assertEqual(response.status_code, 403)
def test_public_user_delete(self):
"""Public user can't get delete notifications"""
for t in Trigger.objects.all():
for t in Notification.objects.all():
url = reverse('userprofile-delete', args=[t.id])
response = self.request_as_user(url, "GET")
self.assertEqual(response.status_code, 403)
......
......@@ -17,11 +17,11 @@ urlpatterns = [
#url(r'^contact/edit/(?P<id>[\d]+)$', views.editContact,
# name="userprofile-edit-contact"),
# /options/trigger/
url(r'^trigger/create$', views.create, name="userprofile-create"),
url(r'^trigger/delete/(?P<id>[\d]+)$', views.delete,
# /options/notification/
url(r'^notification/create$', views.create, name="userprofile-create"),
url(r'^notification/delete/(?P<id>[\d]+)$', views.delete,
name="userprofile-delete"),
#url(r'^trigger/edit/(?P<id>[\d]+)$', views.edit, name="userprofile-edit"),
#url(r'^notification/edit/(?P<id>[\d]+)$', views.edit, name="userprofile-edit"),
# /options/manage_password
url(r'^manage_password$', views.managePassword,
......
......@@ -21,8 +21,8 @@ import socket
import logging
log = logging.getLogger(__name__)
from .models import Trigger, Contact
from .forms import ContactForm, triggerFormFactory
from .models import Notification, Contact
from .forms import ContactForm, notificationFormFactory
from alerts.phone import get_twilio_from
from events.permission_utils import internal_user_required, \
lvem_user_required, is_external
......@@ -34,9 +34,9 @@ from search.query.labels import labelQuery
#@internal_user_required
@login_required
def index(request):
triggers = Trigger.objects.filter(user=request.user)
notifications = Notification.objects.filter(user=request.user)
contacts = Contact.objects.filter(user=request.user)
d = { 'triggers': triggers, 'contacts': contacts }
d = { 'notifications': notifications, 'contacts': contacts }
return render(request, 'profile/notifications.html', context=d)
......@@ -78,21 +78,21 @@ def managePassword(request):
@internal_user_required
def create(request):
"""Create a notification (Trigger) via the web interface"""
"""Create a notification (Notification) via the web interface"""
if request.method == "POST":
form = triggerFormFactory(request.POST, user=request.user)
form = notificationFormFactory(request.POST, user=request.user)
if form.is_valid():
# Create the Trigger
t = Trigger(user=request.user)
# Create the Notification
t = Notification(user=request.user)
labels = form.cleaned_data['labels']
pipelines = form.cleaned_data['pipelines']
contacts = form.cleaned_data['contacts']
farThresh = form.cleaned_data['farThresh']
far_threshold = form.cleaned_data['far_threshold']
label_query = form.cleaned_data['label_query']
# TODO: properly handle negated labels
# If we've got a label query defined for this trigger, then we want
# If we've got a label query defined for this notification, then we want
# each label mentioned in the query to be listed in the event's
# labels. It would be smarter to make sure the label isn't being
# negated, but we can just leave that for later.
......@@ -119,7 +119,7 @@ def create(request):
t.labels = labels
t.pipelines = pipelines
t.contacts = contacts
t.farThresh = farThresh
t.far_threshold = far_threshold
t.label_query = label_query
t.save()
messages.info(request, 'Created notification: {n}.'.format(
......@@ -131,7 +131,7 @@ def create(request):
return HttpResponseRedirect(reverse(index))
else:
form = triggerFormFactory(user=request.user)
form = notificationFormFactory(user=request.user)
return render(request, 'profile/createNotification.html',
context={"form": form})
......@@ -142,8 +142,8 @@ def edit(request, id):
@internal_user_required
def delete(request, id):
try:
t = Trigger.objects.get(id=id)
except Trigger.DoesNotExist:
t = Notification.objects.get(id=id)
except Notification.DoesNotExist:
raise Http404
if request.user != t.user:
return HttpResponseForbidden(("You are not allowed to modify another "
......
......@@ -44,7 +44,7 @@ def labelQuery(s, names=False):
label = Or([CaselessKeyword(n) for n in labelNames])
# If the filter objects are going to be applied to Lable
# objects to retrieve labels by name, names = True.
# This is useful for the label query in userprofile.models.Trigger
# This is useful for the label query in alerts.models.Notification
if names:
label.setParseAction( lambda toks: Q(name=toks[0]) )
else:
......
......@@ -49,11 +49,11 @@
<br/><br/>
<h2>Notifications (LVC Users)</h2>
{% for trigger in triggers %}
{% for notification in notifications %}
<ul>
<li>
<a href="{% url "userprofile-delete" trigger.id %}">Delete</a>
{{ trigger.userlessDisplay }}
<a href="{% url "userprofile-delete" notification.id %}">Delete</a>
{{ notification.userlessDisplay }}
</li>
</ul>
{% endfor %}
......
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