Allow use of dynamic payloads in alert receive channels preview templ… (#1756)

…ate in private api

# What this PR does

## Which issue(s) this PR fixes

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
This commit is contained in:
Ildar Iskhakov 2023-04-18 11:57:40 +08:00 committed by GitHub
parent 7dd726622a
commit 5da5b8d430
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 10 deletions

View file

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Helm chart: add the option to use a helm hook for the migration job ([1386](https://github.com/grafana/oncall/pull/1386))
- Add endpoints to start and stop maintenance in alert receive channel private api ([1755](https://github.com/grafana/oncall/pull/1755))
- Send demo alert with dynamic payload and get demo payload example on private api ([1700](https://github.com/grafana/oncall/pull/1700))
- Allow use of dynamic payloads in alert receive channels preview template in private api ([1756](https://github.com/grafana/oncall/pull/1756))
## v1.2.11 (2023-04-14)

View file

@ -505,6 +505,44 @@ def test_alert_receive_channel_preview_template_require_notification_channel(
assert response.status_code == status.HTTP_200_OK
@pytest.mark.django_db
@pytest.mark.parametrize("template_name", ["title", "message", "image_url"])
@pytest.mark.parametrize("notification_channel", ["slack", "web", "telegram"])
def test_alert_receive_channel_preview_template_dynamic_payload(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
template_name,
notification_channel,
make_alert_group,
make_alert,
):
organization, user, token = make_organization_and_user_with_plugin_token()
alert_receive_channel = make_alert_receive_channel(organization)
alert_group = make_alert_group(alert_receive_channel)
make_alert(alert_group=alert_group, raw_request_data=alert_receive_channel.config.example_payload)
client = APIClient()
url = reverse(
"api-internal:alert_receive_channel-preview-template", kwargs={"pk": alert_receive_channel.public_primary_key}
)
data = {
"template_body": "{{ payload.foo }}",
"template_name": f"{notification_channel}_{template_name}",
"payload": {"foo": "bar"},
}
response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
if notification_channel == "web" and template_name == "message":
assert response.data["preview"] == "<p>bar</p>"
else:
assert response.data["preview"] == "bar"
@pytest.mark.django_db
@pytest.mark.parametrize(
"role,expected_status",

View file

@ -657,5 +657,5 @@ class AlertGroupView(
)
# This method is required for PreviewTemplateMixin
def get_alert_to_template(self):
def get_alert_to_template(self, payload=None):
return self.get_object().alerts.first()

View file

@ -8,7 +8,7 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from apps.alerts.models import AlertReceiveChannel
from apps.alerts.models import Alert, AlertGroup, AlertReceiveChannel
from apps.alerts.models.maintainable_object import MaintainableObject
from apps.api.permissions import RBACPermission
from apps.api.serializers.alert_receive_channel import (
@ -22,6 +22,7 @@ from common.api_helpers.exceptions import BadRequest
from common.api_helpers.filters import ByTeamModelFieldFilterMixin, TeamModelMultipleChoiceFilter
from common.api_helpers.mixins import (
FilterSerializerMixin,
PreviewTemplateException,
PreviewTemplateMixin,
PublicPrimaryKeyMixin,
TeamFilteringMixin,
@ -228,9 +229,16 @@ class AlertReceiveChannelView(
return Response(response)
# This method is required for PreviewTemplateMixin
def get_alert_to_template(self):
def get_alert_to_template(self, payload=None):
try:
return self.get_object().alert_groups.last().alerts.first()
if payload is None:
return self.get_object().alert_groups.last().alerts.first()
else:
if type(payload) != dict:
raise PreviewTemplateException("Payload must be a valid json object")
# Build Alert and AlertGroup objects to pass to templater without saving them to db
alert_group_to_template = AlertGroup(channel=self.get_object())
return Alert(raw_request_data=payload, group=alert_group_to_template)
except AttributeError:
return None

View file

@ -283,11 +283,16 @@ BEHAVIOUR_TEMPLATE_NAMES = [RESOLVE_CONDITION, ACKNOWLEDGE_CONDITION, GROUPING_I
ALL_TEMPLATE_NAMES = APPEARANCE_TEMPLATE_NAMES + BEHAVIOUR_TEMPLATE_NAMES
class PreviewTemplateException(Exception):
pass
class PreviewTemplateMixin:
@action(methods=["post"], detail=True)
def preview_template(self, request, pk):
template_body = request.data.get("template_body", None)
template_name = request.data.get("template_name", None)
payload = request.data.get("payload", None)
if template_body is None or template_name is None:
response = {"preview": None}
@ -295,18 +300,21 @@ class PreviewTemplateMixin:
notification_channel, attr_name = self.parse_name_and_notification_channel(template_name)
if attr_name is None:
raise BadRequest(detail={"template_name": "Attr name is required"})
raise BadRequest(detail={"template_name": "Template name is missing"})
if attr_name not in ALL_TEMPLATE_NAMES:
raise BadRequest(detail={"template_name": "Unknown attr name"})
raise BadRequest(detail={"template_name": "Unknown template name"})
if attr_name in APPEARANCE_TEMPLATE_NAMES:
if notification_channel is None:
raise BadRequest(detail={"notification_channel": "notification_channel is required"})
if notification_channel not in NOTIFICATION_CHANNEL_OPTIONS:
raise BadRequest(detail={"notification_channel": "Unknown notification_channel"})
alert_to_template = self.get_alert_to_template()
if alert_to_template is None:
raise BadRequest(detail="Alert to preview does not exist")
try:
alert_to_template = self.get_alert_to_template(payload=payload)
if alert_to_template is None:
raise BadRequest(detail="Alert to preview does not exist")
except PreviewTemplateException as e:
raise BadRequest(detail=str(e))
if attr_name in APPEARANCE_TEMPLATE_NAMES:
@ -337,7 +345,7 @@ class PreviewTemplateMixin:
response = {"preview": templated_attr}
return Response(response, status=status.HTTP_200_OK)
def get_alert_to_template(self):
def get_alert_to_template(self, payload=None):
raise NotImplementedError
@staticmethod