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:
parent
7dd726622a
commit
5da5b8d430
5 changed files with 65 additions and 10 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue