@ -8,6 +8,7 @@ try:
except ImportError :
from yaml import Loader , Dumper
import orjson
from asgiref . sync import async_to_sync
from core . lib . notify import sendmsg
@ -29,20 +30,41 @@ class RuleParseError(Exception):
def rule_matched ( rule , message , matched ) :
title = f " Rule { rule . name } matched "
# Dump the message in YAML for readability
message = dump ( message , Dumper = Dumper , default_flow_style = False )
matched = " , " . join ( [ f " { k } : { v } " for k , v in matched . items ( ) ] )
notify_message = f " { rule . name } match: { matched } \n { message } "
notify_message = notify_message . encode ( " utf-8 " , " replace " )
notification_settings = rule . get_notification_settings ( )
cast = {
" title " : title ,
" priority " : str ( rule . priority ) ,
* * notification_settings ,
}
if rule . topic is not None :
cast [ " topic " ] = rule . topic
if rule . service == " ntfy " :
# Dump the message in YAML for readability
messages_formatted = " "
if isinstance ( message , list ) :
for message in message :
messages_formatted + = dump (
message , Dumper = Dumper , default_flow_style = False
)
messages_formatted + = " \n "
else :
messages_formatted = dump ( message , Dumper = Dumper , default_flow_style = False )
matched = " , " . join ( [ f " { k } : { v } " for k , v in matched . items ( ) ] )
notify_message = f " { rule . name } match: { matched } \n { messages_formatted } "
notify_message = notify_message . encode ( " utf-8 " , " replace " )
elif rule . service == " webhook " :
notify_message = {
" rule_id " : rule . id ,
" rule_name " : rule . name ,
" match " : matched ,
" data " : message ,
}
if " priority " in notification_settings :
notify_message [ " priority " ] = notification_settings [ " priority " ]
if " topic " in notification_settings :
notify_message [ " topic " ] = notification_settings [ " topic " ]
notify_message = orjson . dumps ( notify_message )
sendmsg ( rule . user , notify_message , * * cast )
@ -135,7 +157,9 @@ class NotificationRuleData(object):
current_match = self . get_match ( index )
if current_match is False :
formatted_aggs = self . format_aggs ( aggs )
rule_matched ( self . object , results [ : 5 ] , formatted_aggs )
rule_matched (
self . object , results [ : self . object . amount ] , formatted_aggs
)
self . store_match ( index , True )
continue
self . store_match ( index , False )
@ -238,16 +262,36 @@ class NotificationRuleData(object):
"""
interval = self . cleaned_data . get ( " interval " )
window = self . cleaned_data . get ( " window " )
if interval == 0 and window is not None :
amount = self . cleaned_data . get ( " amount " )
on_demand = interval == 0
if on_demand and window is not None :
# Interval is on demand and window is specified
# We can't have a window with on-demand rules
raise RuleParseError (
" Window cannot be specified with on-demand interval " , " window "
)
if interval != 0 and window is None :
if not on_demand and window is None :
# Interval is not on demand and window is not specified
# We can't have a non-on-demand interval without a window
raise RuleParseError (
" Window must be specified with non-on-demand interval " , " window "
)
if not on_demand and amount is None :
# Interval is not on demand and amount is not specified
# We can't have a non-on-demand interval without an amount
raise RuleParseError (
" Amount must be specified with non-on-demand interval " , " amount "
)
if on_demand and amount is not None :
# Interval is on demand and amount is specified
# We can't have an amount with on-demand rules
raise RuleParseError (
" Amount cannot be specified with on-demand interval " , " amount "
)
if window is not None :
window_number = window [ : - 1 ]
if not window_number . isdigit ( ) :