Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions alerta/database/backends/postgres/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1356,9 +1356,9 @@ def delete_delayed_notification(self, id):
def create_notification_rule(self, notification_rule):
insert = """
INSERT INTO notification_rules (id, name, active, priority, environment, service, resource, event, tags, reactivate, excluded_tags, delay_time,
customer, "user", create_time, start_time, end_time, days, receivers, users_emails, group_ids, use_oncall, text, channel_id, triggers)
customer, "user", create_time, start_time, end_time, days, receivers, users_emails, group_ids, use_oncall, text, subject, channel_id, triggers)
VALUES (%(id)s, %(name)s, %(active)s, %(priority)s, %(environment)s, %(service)s, %(resource)s, %(event)s, %(tags)s, %(reactivate)s, %(excluded_tags)s, %(delay_time)s,
%(customer)s, %(user)s, %(create_time)s, %(start_time)s, %(end_time)s, %(days)s, %(receivers)s, %(users_emails)s, %(group_ids)s, %(use_oncall)s, %(text)s, %(channel_id)s, %(triggers)s::notification_triggers[] )
%(customer)s, %(user)s, %(create_time)s, %(start_time)s, %(end_time)s, %(days)s, %(receivers)s, %(users_emails)s, %(group_ids)s, %(use_oncall)s, %(text)s, %(subject)s, %(channel_id)s, %(triggers)s::notification_triggers[] )
RETURNING *
"""
return self._insert(insert, vars(notification_rule))
Expand Down Expand Up @@ -1617,6 +1617,8 @@ def update_notification_rule(self, id, **kwargs):
update += 'triggers=%(triggers)s::notification_triggers[], '
if 'text' in kwargs:
update += 'text=%(text)s, '
if 'subject' in kwargs:
update += 'subject=%(subject)s, '
if 'channelId' in kwargs:
update += 'channel_id=%(channelId)s,'
if 'active' in kwargs:
Expand Down
5 changes: 5 additions & 0 deletions alerta/models/notification_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ def __init__(
kwargs['create_time'] if 'create_time' in kwargs else datetime.now(UTC)
)
self.text = kwargs.get('text', None)
self.subject = kwargs.get('subject', None)

if self.environment:
self.priority = 1
Expand Down Expand Up @@ -269,6 +270,7 @@ def parse(cls, json: JSON) -> 'NotificationRule':
else None,
user=json.get('user', None),
text=json.get('text', None),
subject=json.get('subject', None),
days=json.get('days', None),
)
return notification_rule
Expand Down Expand Up @@ -299,6 +301,7 @@ def serialize(self) -> Dict[str, Any]:
'createTime': self.create_time,
'reactivate': self.reactivate,
'text': self.text,
'subject': self.subject,
'startTime': self.start_time.strftime('%H:%M')
if self.start_time is not None
else None,
Expand Down Expand Up @@ -354,6 +357,7 @@ def from_document(cls, doc: Dict[str, Any]) -> 'NotificationRule':
create_time=doc.get('createTime', None),
reactivate=doc.get('reactivate', None),
text=doc.get('text', None),
subject=doc.get('subject', None),
start_time=(
datetime.strptime(
f'{doc["startTime"]:.2f}'.replace('.', ':'), '%H:%M'
Expand Down Expand Up @@ -400,6 +404,7 @@ def from_record(cls, rec) -> 'NotificationRule':
create_time=rec.create_time,
reactivate=rec.reactivate,
text=rec.text,
subject=rec.subject,
start_time=rec.start_time,
end_time=rec.end_time,
days=rec.days,
Expand Down
25 changes: 14 additions & 11 deletions alerta/plugins/notification_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,22 +123,22 @@ def send_link_mobility_xml(message: str, channel: NotificationChannel, receivers
return requests.post(f'{channel.host}', data, headers=headers, verify=channel.verify if channel.verify is None or channel.verify.lower() != 'false' else False)


def send_smtp_mail(message: str, channel: NotificationChannel, receivers: set, fernet: Fernet, **kwargs):
def send_smtp_mail(message: str, channel: NotificationChannel, receivers: set, fernet: Fernet, subject: str, **kwargs):
server = smtplib.SMTP_SSL(channel.host)
api_sid = fernet.decrypt(channel.api_sid.encode()).decode()
api_token = fernet.decrypt(channel.api_token.encode()).decode()
server.login(api_sid, api_token)
server.sendmail(channel.sender, list(receivers), f"From: {channel.sender}\nTo: {','.join(receivers)}\nSubject: Alerta\n\n{message}")
server.sendmail(channel.sender, list(receivers), f"From: {channel.sender}\nTo: {','.join(receivers)}\nSubject: {subject}\n\n{message}")
server.quit()


def send_email(message: str, channel: NotificationChannel, receivers: set, fernet: Fernet, **kwargs):
def send_email(message: str, channel: NotificationChannel, receivers: set, fernet: Fernet, subject: str, **kwargs):
data = {
'personalizations': [
{'to': [{'email': email} for email in receivers]}
],
'from': {'email': channel.sender},
'subject': 'Alerta',
'subject': subject,
'content': [{'type': 'text/html', 'value': message.replace('\n', '<br>')}],
}
api_token = fernet.decrypt(channel.api_token.encode()).decode()
Expand Down Expand Up @@ -193,7 +193,7 @@ def delay_notification(alert: Alert, notification_rule: NotificationRule):
}).create()


def handle_channel(message: str, channel: NotificationChannel, notification_rule: NotificationRule, users: 'set[NotificationInfo]', fernet: Fernet, alert: str):
def handle_channel(message: str, channel: NotificationChannel, notification_rule: NotificationRule, users: 'set[NotificationInfo]', fernet: Fernet, alert: str, subject: str):
notification_type = channel.type
phone_numbers = {*notification_rule.receivers, *[f'{user.country_code}{user.phone_number}' for user in users if user.phone_number is not None]}
mails = {*[receiver.lower() for receiver in notification_rule.receivers], *[user.email.lower() for user in users if user.email is not None]}
Expand All @@ -202,7 +202,7 @@ def handle_channel(message: str, channel: NotificationChannel, notification_rule
if len(mails) == 0:
return
try:
response = send_email(message, channel, mails, fernet)
response = send_email(message, channel, mails, fernet, subject)
if response.status_code != 202:
data = response.json()['errors'][0]
log_notification(False, message, channel, notification_rule.id, alert, mails, f'Got status code {response.status_code}: {data["message"]}')
Expand All @@ -217,7 +217,7 @@ def handle_channel(message: str, channel: NotificationChannel, notification_rule
if len(mails) == 0:
return
try:
send_smtp_mail(message, channel, mails, fernet)
send_smtp_mail(message, channel, mails, fernet, subject)
log_notification(True, message, channel, notification_rule.id, alert, mails)
except InvalidToken:
log_notification(False, message, channel, notification_rule.id, alert, mails, 'NotificationChannel: Failed to decrypt authentication keys')
Expand Down Expand Up @@ -278,9 +278,10 @@ def handle_channel(message: str, channel: NotificationChannel, notification_rule

def handle_test(channel: NotificationChannel, info: NotificationRule, config):
message = info.text if info.text != '' else 'this is a test message for testing a notification_channel in alerta'
subject = info.subject if info.subject != '' and info.subject is not None else 'Alerta Test Notification'
fernet = Fernet(config['NOTIFICATION_KEY'])
channel = update_bearer(channel, fernet)
handle_channel(message, channel, info, info.users, fernet, 'Test Notification Channel')
handle_channel(message, channel, info, info.users, fernet, 'Test Notification Channel', subject)


def get_notification_trigger_text(rule: NotificationRule, alert: Alert, status: str):
Expand All @@ -294,19 +295,21 @@ def get_notification_trigger_text(rule: NotificationRule, alert: Alert, status:
def handle_notifications(alert: 'Alert', notifications: 'list[tuple[NotificationRule,NotificationChannel, list[set[NotificationInfo | None]]]]', on_users: 'list[set[NotificationInfo | None]]', fernet: Fernet, app_context, status: str = ''):
app_context.push()
standard_message = '%(environment)s: %(severity)s alert for %(service)s - %(resource)s is %(event)s'
default_subject = 'Alerta Notification'
for notification_rule, channel, users in notifications:
if channel is None:
return

if notification_rule.use_oncall:
users.update(on_users)
msg_obj = {**alert.serialize, 'status': status} if status != '' else alert.serialize
msg_obj = get_message_obj({**alert.serialize, 'status': status} if status != '' else alert.serialize)
text = get_notification_trigger_text(notification_rule, alert, status)
message = (
text if text != '' and text is not None else standard_message
) % get_message_obj(msg_obj)
) % msg_obj
subject = (notification_rule.subject if notification_rule.subject != '' and notification_rule.subject is not None else default_subject) % msg_obj

handle_channel(message, channel, notification_rule, users, fernet, alert.id)
handle_channel(message, channel, notification_rule, users, fernet, alert.id, subject)


def handle_alert(alert: Alert, config, stat: str = ''):
Expand Down
6 changes: 6 additions & 0 deletions alerta/sql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,12 @@ BEGIN
END $$;


DO $$
BEGIN
ALTER TABLE notification_rules ADD COLUMN "subject" text;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'column "subject" already exists in notification_rules.';
END$$;
DO $$
BEGIN
ALTER TABLE notification_rules ADD COLUMN delay_time interval;
Expand Down
2 changes: 1 addition & 1 deletion alerta/views/notification_sends.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def notification_send(notification_channel_id):
users = [NotificationSendInfo.find_by_id(notification['id']).email for notification in data['notifications'] if notification['type'] == 'User']
groups = [notification['id'] for notification in data['notifications'] if notification['type'] == 'Group']
try:
notification_rule = NotificationRule.parse({'usersEmails': users, 'groupIds': groups, 'receivers': [], 'text': data['text'], 'channelId': notification_channel_id, 'environment': plugins.config.get('DEFAULT_ENVIRONMENT')})
notification_rule = NotificationRule.parse({'usersEmails': users, 'groupIds': groups, 'receivers': [], 'text': data['text'], 'subject': data.get('subject'), 'channelId': notification_channel_id, 'environment': plugins.config.get('DEFAULT_ENVIRONMENT')})
except Exception as e:
raise ApiError(str(e), 400)
try:
Expand Down
Loading