Skip to content
Snippets Groups Projects
Commit 8a8fe4b8 authored by Tanner Prestegard's avatar Tanner Prestegard Committed by GraceDB
Browse files

Enhancements to Contact and Notification forms

parent 23f6185d
No related branches found
No related tags found
No related merge requests found
...@@ -36,22 +36,46 @@ class BaseNotificationForm(forms.ModelForm): ...@@ -36,22 +36,46 @@ class BaseNotificationForm(forms.ModelForm):
fields = ['description'] # dummy placeholder fields = ['description'] # dummy placeholder
labels = { labels = {
'far_threshold': 'FAR Threshold (Hz)', 'far_threshold': 'FAR Threshold (Hz)',
'ns_candidate': 'Neutron star candidate',
} }
help_texts = { help_texts = {
'contacts': ('If this box is empty, you must create and verify a ' 'contacts': textwrap.dedent("""\
'contact.'), Select a contact or contacts to receive the notification.
If this box is empty, you must create and verify a contact.
""").rstrip(),
'far_threshold': textwrap.dedent("""\
Require that the candidate has FAR less than this threshold.
Leave blank to place no requirement on FAR.
""").rstrip(),
'labels': textwrap.dedent("""\
Require that a label or labels must be attached to the
candidate. You can specify labels here or in the label query,
but not both.
""").rstrip(),
'label_query': textwrap.dedent("""\ 'label_query': textwrap.dedent("""\
Require that the candidate's set of labels matches this query.
Label names can be combined with binary AND: ('&' or ',') Label names can be combined with binary AND: ('&' or ',')
or binary OR: '|'. They can also be negated with '~' or '-'. or binary OR: '|'. They can also be negated with '~' or '-'.
For N labels, there must be exactly N-1 binary operators. For N labels, there must be exactly N-1 binary operators.
Parentheses are not allowed. Parentheses are not allowed.
""").rstrip() """).rstrip(),
'ns_candidate': ('Require that the candidate has m<sub>2</sub> '
'< 3.0 M<sub>sun</sub>.'),
}
widgets = {
'contacts': forms.widgets.SelectMultiple(attrs={'size': 5}),
'far_threshold': forms.widgets.TextInput(),
'labels': forms.widgets.SelectMultiple(attrs={'size': 8}),
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None) user = kwargs.pop('user', None)
super(BaseNotificationForm, self).__init__(*args, **kwargs) super(BaseNotificationForm, self).__init__(*args, **kwargs)
# We need a user for this to work
assert user is not None
assert user.is_authenticated
# Dynamically set contacts queryset to be only contacts that: # Dynamically set contacts queryset to be only contacts that:
# a) belong to the user # a) belong to the user
# b) are verified # b) are verified
...@@ -59,6 +83,10 @@ class BaseNotificationForm(forms.ModelForm): ...@@ -59,6 +83,10 @@ class BaseNotificationForm(forms.ModelForm):
self.fields['contacts'].queryset = user.contact_set.filter( self.fields['contacts'].queryset = user.contact_set.filter(
verified=True) verified=True)
# Sort the queryset for labels by name
self.fields['labels'].queryset = \
self.fields['labels'].queryset.order_by('name')
def clean(self): def clean(self):
cleaned_data = super(BaseNotificationForm, self).clean() cleaned_data = super(BaseNotificationForm, self).clean()
...@@ -71,7 +99,8 @@ class BaseNotificationForm(forms.ModelForm): ...@@ -71,7 +99,8 @@ class BaseNotificationForm(forms.ModelForm):
labels = cleaned_data.get('labels', None) labels = cleaned_data.get('labels', None)
# Can't specify a label from the list and a label query # Can't specify a label from the list and a label query
if label_query is not None and labels is not None: # No label specified in the form looks like an empty queryset here
if label_query is not None and (labels is not None and labels.exists()):
err_msg = ('Cannot specify both labels and label query, ' err_msg = ('Cannot specify both labels and label query, '
'choose one or the other.') 'choose one or the other.')
err_dict[NON_FIELD_ERRORS].append(err_msg) err_dict[NON_FIELD_ERRORS].append(err_msg)
...@@ -93,6 +122,19 @@ class BaseNotificationForm(forms.ModelForm): ...@@ -93,6 +122,19 @@ class BaseNotificationForm(forms.ModelForm):
return cleaned_data return cleaned_data
def clean_far_threshold(self):
far_threshold = self.cleaned_data['far_threshold']
# If it's set, make sure it's positive
if far_threshold is not None:
# We can assume it's a float due to previous
# validation/cleaning
if (far_threshold <= 0):
raise forms.ValidationError(
'FAR threshold must be a positive number.')
return far_threshold
class SupereventNotificationForm(BaseNotificationForm, MultipleForm): class SupereventNotificationForm(BaseNotificationForm, MultipleForm):
key = 'superevent' key = 'superevent'
...@@ -108,15 +150,40 @@ class EventNotificationForm(BaseNotificationForm, MultipleForm): ...@@ -108,15 +150,40 @@ class EventNotificationForm(BaseNotificationForm, MultipleForm):
category = Notification.NOTIFICATION_CATEGORY_EVENT category = Notification.NOTIFICATION_CATEGORY_EVENT
# Remove 'Test' group # Remove 'Test' group
groups = forms.ModelMultipleChoiceField(queryset= groups = forms.ModelMultipleChoiceField(queryset=
Group.objects.exclude(name='Test')) Group.objects.exclude(name='Test').order_by('name'), required=False,
help_text=("Require that the analysis group for the candidate is "
"this group or in this set of groups. Leave blank to place no "
"requirement on group."))
# Remove 'MDC' and 'O2VirgoTest' searches # Remove 'MDC' and 'O2VirgoTest' searches
searches = forms.ModelMultipleChoiceField(queryset= searches = forms.ModelMultipleChoiceField(queryset=
Search.objects.exclude(name__in=['MDC', 'O2VirgoTest'])) Search.objects.exclude(name__in=['MDC', 'O2VirgoTest']).order_by('name'),
required=False, widget=forms.widgets.SelectMultiple(attrs={'size': 6}),
help_text=("Require that the analysis search for the candidate is "
"this search or in this set of searches. Leave blank to place no "
"requirement on search."))
class Meta(BaseNotificationForm.Meta): class Meta(BaseNotificationForm.Meta):
fields = ['description', 'contacts', 'far_threshold', 'groups', fields = ['description', 'contacts', 'far_threshold', 'groups',
'pipelines', 'searches', 'labels', 'label_query', 'ns_candidate', 'pipelines', 'searches', 'labels', 'label_query', 'ns_candidate',
'key_field'] 'key_field']
help_texts = BaseNotificationForm.Meta.help_texts
help_texts.update({'pipelines': textwrap.dedent("""\
Require that the analysis pipeline for the candidate is this
pipeline or in this set of pipelines. Leave blank to place no
requirement on pipeline.
""").rstrip()
})
widgets = BaseNotificationForm.Meta.widgets
widgets.update({
'pipelines': forms.widgets.SelectMultiple(attrs={'size': 6}),
})
def __init__(self, *args, **kwargs):
super(EventNotificationForm, self).__init__(*args, **kwargs)
# Sort the queryset for pipelines by name
self.fields['pipelines'].queryset = \
self.fields['pipelines'].queryset.order_by('name')
############################################################################### ###############################################################################
...@@ -128,6 +195,13 @@ class PhoneContactForm(forms.ModelForm, MultipleForm): ...@@ -128,6 +195,13 @@ class PhoneContactForm(forms.ModelForm, MultipleForm):
class Meta: class Meta:
model = Contact model = Contact
fields = ['description', 'phone', 'phone_method', 'key_field'] fields = ['description', 'phone', 'phone_method', 'key_field']
labels = {
'phone': 'Phone number',
}
help_texts = {
'phone': ('Non-US numbers should include the country code, '
'including the preceding \'+\'.'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PhoneContactForm, self).__init__(*args, **kwargs) super(PhoneContactForm, self).__init__(*args, **kwargs)
...@@ -140,6 +214,9 @@ class EmailContactForm(forms.ModelForm, MultipleForm): ...@@ -140,6 +214,9 @@ class EmailContactForm(forms.ModelForm, MultipleForm):
class Meta: class Meta:
model = Contact model = Contact
fields = ['description', 'email', 'key_field'] fields = ['description', 'email', 'key_field']
labels = {
'email': 'Email address',
}
class VerifyContactForm(forms.ModelForm): class VerifyContactForm(forms.ModelForm):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment