2022-07-21 12:45:44 +00:00
from django import forms
from django . contrib . auth . forms import UserCreationForm
2023-01-11 21:04:54 +00:00
from django . core . exceptions import FieldDoesNotExist
2023-01-12 07:20:43 +00:00
from django . forms import ModelForm
2022-07-21 12:45:44 +00:00
2023-01-15 17:59:12 +00:00
from core . db . storage import db
from core . lib . parsing import QueryError
2023-01-14 14:45:19 +00:00
from core . lib . rules import NotificationRuleData , RuleParseError
2023-01-12 07:20:43 +00:00
from . models import NotificationRule , NotificationSettings , User
2022-07-21 12:45:44 +00:00
2023-01-14 14:36:46 +00:00
# flake8: noqa: E501
2023-01-11 21:04:54 +00:00
class RestrictedFormMixin :
"""
This mixin is used to restrict the queryset of a form to the current user .
The request object is passed from the view .
Fieldargs is used to pass additional arguments to the queryset filter .
"""
fieldargs = { }
def __init__ ( self , * args , * * kwargs ) :
# self.fieldargs = {}
self . request = kwargs . pop ( " request " )
super ( ) . __init__ ( * args , * * kwargs )
for field in self . fields :
# Check it's not something like a CharField which has no queryset
if not hasattr ( self . fields [ field ] , " queryset " ) :
continue
model = self . fields [ field ] . queryset . model
# Check if the model has a user field
try :
model . _meta . get_field ( " user " )
# Add the user to the queryset filters
self . fields [ field ] . queryset = model . objects . filter (
user = self . request . user , * * self . fieldargs . get ( field , { } )
)
except FieldDoesNotExist :
pass
2022-07-21 12:45:44 +00:00
class NewUserForm ( UserCreationForm ) :
email = forms . EmailField ( required = True )
class Meta :
model = User
fields = (
" username " ,
" email " ,
" first_name " ,
" last_name " ,
" password1 " ,
" password2 " ,
)
def save ( self , commit = True ) :
user = super ( NewUserForm , self ) . save ( commit = False )
user . email = self . cleaned_data [ " email " ]
if commit :
user . save ( )
return user
class CustomUserCreationForm ( UserCreationForm ) :
class Meta :
model = User
fields = " __all__ "
2023-01-12 07:20:43 +00:00
class NotificationSettingsForm ( RestrictedFormMixin , ModelForm ) :
class Meta :
model = NotificationSettings
fields = (
2023-01-15 18:40:17 +00:00
" topic " ,
" url " ,
" service " ,
2023-01-12 07:20:43 +00:00
)
help_texts = {
2023-01-15 18:40:17 +00:00
" topic " : " The topic to send notifications to. " ,
" url " : " Custom NTFY server/webhook destination. Leave blank to use the default server for NTFY. For webhooks this field is required. " ,
" service " : " The service to use for notifications. " ,
2023-01-12 07:20:43 +00:00
}
2023-01-15 18:40:17 +00:00
def clean ( self ) :
cleaned_data = super ( NotificationSettingsForm , self ) . clean ( )
if " service " in cleaned_data :
if cleaned_data [ " service " ] == " webhook " :
if not cleaned_data . get ( " url " ) :
self . add_error (
" url " ,
" You must set a URL for webhooks. " ,
)
2023-01-12 07:20:43 +00:00
class NotificationRuleForm ( RestrictedFormMixin , ModelForm ) :
class Meta :
model = NotificationRule
fields = (
" name " ,
2023-01-12 07:20:48 +00:00
" data " ,
2023-01-14 14:36:46 +00:00
" interval " ,
" window " ,
2023-01-15 23:02:13 +00:00
" amount " ,
2023-01-12 07:20:48 +00:00
" priority " ,
2023-01-12 07:20:48 +00:00
" topic " ,
2023-01-15 20:27:19 +00:00
" url " ,
" service " ,
2023-01-16 00:10:41 +00:00
" send_empty " ,
2023-01-12 07:20:43 +00:00
" enabled " ,
)
help_texts = {
" name " : " The name of the rule. " ,
2023-01-14 14:36:46 +00:00
" priority " : " The notification priority of the rule. " ,
2023-01-15 18:40:17 +00:00
" url " : " Custom NTFY server/webhook destination. Leave blank to use the default server for NTFY. For webhooks this field is required. " ,
" service " : " The service to use for notifications " ,
2023-01-12 07:20:48 +00:00
" topic " : " The topic to send notifications to. Leave blank for default. " ,
2023-01-12 07:20:43 +00:00
" enabled " : " Whether the rule is enabled. " ,
" data " : " The notification rule definition. " ,
2023-01-14 16:36:22 +00:00
" interval " : " How often to run the search. On demand evaluates messages as they are received, without running a scheduled search. The remaining options schedule a search of the database with the window below. " ,
2023-01-14 14:36:46 +00:00
" window " : " Time window to search: 1d, 1h, 1m, 1s, etc. " ,
2023-01-15 23:02:13 +00:00
" amount " : " Amount of matches to be returned for scheduled queries. Cannot be used with on-demand queries. " ,
2023-01-16 00:10:41 +00:00
" send_empty " : " Send a notification if no matches are found. " ,
2023-01-12 07:20:43 +00:00
}
def clean ( self ) :
cleaned_data = super ( NotificationRuleForm , self ) . clean ( )
2023-01-15 18:40:17 +00:00
if " service " in cleaned_data :
if cleaned_data [ " service " ] == " webhook " :
if not cleaned_data . get ( " url " ) :
self . add_error (
" url " ,
" You must set a URL for webhooks. " ,
)
2023-01-12 07:20:43 +00:00
try :
2023-01-15 17:59:12 +00:00
# Passing db to avoid circular import
parsed_data = NotificationRuleData ( self . request . user , cleaned_data , db = db )
parsed_data . test_schedule ( )
2023-01-14 14:45:19 +00:00
except RuleParseError as e :
self . add_error ( e . field , f " Parsing error: { e } " )
2023-01-12 07:20:43 +00:00
return
except QueryError as e :
self . add_error ( " data " , f " Query error: { e } " )
return
# Write back the validated data
# We need this to populate the index and source variable if
# they are not set
to_store = str ( parsed_data )
cleaned_data [ " data " ] = to_store
return cleaned_data