Allow Telegram DMs without channel connection (#142)

* allow posting DM messages to Telegram without connecting a channel

* fix get_channel_for_alert_group, add tests

* add docs on usage without channel connection
This commit is contained in:
Vadim Stepanov 2022-06-28 09:11:19 +01:00 committed by GitHub
parent 7169b1b563
commit c8964188e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 48 deletions

View file

@ -20,6 +20,8 @@ You can use Telegram to deliver alert group notifications to a dedicated channel
Each alert group notification is assigned a dedicated discussion. Users can perform notification actions (acknowledge, resolve, silence), create reports, and discuss alerts in the comments section of the discussions.
In case an integration route is not configured to use a Telegram channel, users will receive messages with alert group contents, logs and actions in their DMs.
## Connect to Telegram
Connect your organization's Telegram account to your Grafana OnCall instance by following the instructions provided in OnCall. You can use the following steps as a reference.

View file

@ -1557,14 +1557,6 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models.
else:
return True
@property
def notify_in_telegram_enabled(self):
channel_filter = self.channel_filter_with_respect_to_escalation_snapshot
if channel_filter is not None:
return channel_filter.notify_in_telegram
else:
return True
@property
def is_presented_in_slack(self):
return self.slack_message and self.channel.organization.slack_team_identity

View file

@ -162,10 +162,6 @@ def notify_user_task(
user_to_be_notified_in_slack = (
notification_policy.notify_by == UserNotificationPolicy.NotificationChannel.SLACK
)
user_to_be_notified_in_telegram = (
notification_policy.notify_by == UserNotificationPolicy.NotificationChannel.TELEGRAM
)
if user_to_be_notified_in_slack and alert_group.notify_in_slack_enabled is False:
log_record = UserNotificationPolicyLogRecord(
author=user,
@ -178,18 +174,6 @@ def notify_user_task(
notification_channel=notification_policy.notify_by,
notification_error_code=UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_POSTING_TO_SLACK_IS_DISABLED,
)
elif user_to_be_notified_in_telegram and alert_group.notify_in_telegram_enabled is False:
log_record = UserNotificationPolicyLogRecord(
author=user,
type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED,
notification_policy=notification_policy,
alert_group=alert_group,
reason=reason,
slack_prevent_posting=prevent_posting_to_thread,
notification_step=notification_policy.step,
notification_channel=notification_policy.notify_by,
notification_error_code=UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_POSTING_TO_TELEGRAM_IS_DISABLED,
)
else:
log_record = UserNotificationPolicyLogRecord(
author=user,
@ -292,8 +276,7 @@ def perform_notification(log_record_pk):
)
elif notification_channel == UserNotificationPolicy.NotificationChannel.TELEGRAM:
if alert_group.notify_in_telegram_enabled is True:
TelegramToUserConnector.notify_user(user, alert_group, notification_policy)
TelegramToUserConnector.notify_user(user, alert_group, notification_policy)
# TODO: restore email notifications
# elif notification_channel == UserNotificationPolicy.NotificationChannel.EMAIL:

View file

@ -59,7 +59,7 @@ class UserNotificationPolicyLogRecord(models.Model):
ERROR_NOTIFICATION_MAIL_DELIVERY_FAILED,
ERROR_NOTIFICATION_TELEGRAM_BOT_IS_DELETED,
ERROR_NOTIFICATION_POSTING_TO_SLACK_IS_DISABLED,
ERROR_NOTIFICATION_POSTING_TO_TELEGRAM_IS_DISABLED,
ERROR_NOTIFICATION_POSTING_TO_TELEGRAM_IS_DISABLED, # deprecated
ERROR_NOTIFICATION_IN_SLACK,
ERROR_NOTIFICATION_IN_SLACK_TOKEN_ERROR,
ERROR_NOTIFICATION_IN_SLACK_USER_NOT_IN_SLACK,
@ -213,6 +213,7 @@ class UserNotificationPolicyLogRecord(models.Model):
self.notification_error_code
== UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_POSTING_TO_TELEGRAM_IS_DISABLED
):
# deprecated
result += f"failed to notify {user_verbal} in Telegram, because the incident is not posted to Telegram (reason: Telegram is disabled for the route)"
elif (
self.notification_error_code

View file

@ -66,11 +66,6 @@ class AlertGroupTelegramRepresentative(AlertGroupAbstractRepresentative):
if not isinstance(alert_group, AlertGroup):
alert_group = AlertGroup.all_objects.get(pk=alert_group)
# telegram notification is disabled for channel filter
if alert_group.notify_in_telegram_enabled is False:
logger.debug(f"Skipping alert group with id {alert_group.pk} since notify_in_telegram is disabled")
return
messages_to_edit = alert_group.telegram_messages.filter(
message_type__in=(
TelegramMessage.LOG_MESSAGE,
@ -90,13 +85,6 @@ class AlertGroupTelegramRepresentative(AlertGroupAbstractRepresentative):
if not isinstance(log_record, AlertGroupLogRecord):
log_record = AlertGroupLogRecord.objects.get(pk=log_record)
# telegram notification is disabled for channel filter
if log_record.alert_group.notify_in_telegram_enabled is False:
logger.debug(
f"Skipping alert group with id {log_record.alert_group.pk} since notify_in_telegram is disabled"
)
return
instance = cls(log_record)
if instance.is_applicable():
handler = instance.get_handler()
@ -104,16 +92,7 @@ class AlertGroupTelegramRepresentative(AlertGroupAbstractRepresentative):
@staticmethod
def on_create_alert(**kwargs):
Alert = apps.get_model("alerts", "Alert")
alert_pk = kwargs["alert"]
alert = Alert.objects.get(pk=alert_pk)
# telegram notification is disabled for channel filter
if alert.group.notify_in_telegram_enabled is False:
logger.debug(f"Skipping alert with id {alert.pk} since notify_in_telegram is disabled")
return
on_create_alert_telegram_representative_async.apply_async((alert_pk,))
def get_handler(self):

View file

@ -82,6 +82,9 @@ class TelegramToOrganizationConnector(models.Model):
if alert_group.channel_filter is None:
return default_channel
if not alert_group.channel_filter.notify_in_telegram:
return None
return alert_group.channel_filter.telegram_channel or default_channel
def make_channel_default(self, author):

View file

@ -0,0 +1,66 @@
import pytest
from apps.telegram.models import TelegramMessage, TelegramToOrganizationConnector
@pytest.mark.django_db
def test_get_channel_for_alert_group(
make_organization, make_alert_receive_channel, make_channel_filter, make_alert_group, make_telegram_channel
):
organization = make_organization()
make_telegram_channel(organization, is_default_channel=True)
telegram_channel = make_telegram_channel(organization)
alert_receive_channel = make_alert_receive_channel(organization)
channel_filter = make_channel_filter(
alert_receive_channel, notify_in_telegram=True, telegram_channel=telegram_channel
)
alert_group = make_alert_group(alert_receive_channel, channel_filter=channel_filter)
channel = TelegramToOrganizationConnector.get_channel_for_alert_group(alert_group)
assert channel is telegram_channel
@pytest.mark.django_db
def test_get_channel_telegram_disabled_for_route(
make_organization, make_alert_receive_channel, make_channel_filter, make_alert_group, make_telegram_channel
):
organization = make_organization()
telegram_channel = make_telegram_channel(organization)
alert_receive_channel = make_alert_receive_channel(organization)
channel_filter = make_channel_filter(
alert_receive_channel, notify_in_telegram=False, telegram_channel=telegram_channel
)
alert_group = make_alert_group(alert_receive_channel, channel_filter=channel_filter)
channel = TelegramToOrganizationConnector.get_channel_for_alert_group(alert_group)
assert channel is None
@pytest.mark.django_db
def test_get_channel_for_alert_group_dm_messages_exist(
make_organization,
make_alert_receive_channel,
make_channel_filter,
make_alert_group,
make_telegram_channel,
make_telegram_message,
):
organization = make_organization()
telegram_channel = make_telegram_channel(organization)
alert_receive_channel = make_alert_receive_channel(organization)
channel_filter = make_channel_filter(
alert_receive_channel, notify_in_telegram=True, telegram_channel=telegram_channel
)
alert_group = make_alert_group(alert_receive_channel, channel_filter=channel_filter)
make_telegram_message(alert_group=alert_group, message_type=TelegramMessage.PERSONAL_MESSAGE)
channel = TelegramToOrganizationConnector.get_channel_for_alert_group(alert_group)
assert channel is None