diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 97edd09762..d61c9d2472 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -4227,6 +4227,28 @@ class NotificationTemplateSerializer(BaseSerializer): error_list.append(_("Field '{}' unavailable".format(exc.message))) except SecurityError as exc: error_list.append(_("Security error due to field '{}'".format(exc.message))) + + # Ensure that if a webhook body was provided, that it can be rendered as a dictionary + notification_type = '' + if self.instance: + notification_type = getattr(self.instance, 'notification_type', '') + else: + notification_type = self.initial_data.get('notification_type', '') + + if notification_type == 'webhook': + for event in messages: + if not messages[event]: + continue + body = messages[event].get('body', {}) + if body: + try: + potential_body = json.loads(body) + if not isinstance(potential_body, dict): + error_list.append(_("Webhook body for '{}' should be a json dictionary. Found type '{}'." + .format(event, type(potential_body).__name__))) + except json.JSONDecodeError as exc: + error_list.append(_("Webhook body for '{}' is not a valid json dictionary ({}).".format(event, exc))) + if error_list: raise serializers.ValidationError(error_list) diff --git a/awx/main/notifications/webhook_backend.py b/awx/main/notifications/webhook_backend.py index 1f29fe8bca..92cddf4b3b 100644 --- a/awx/main/notifications/webhook_backend.py +++ b/awx/main/notifications/webhook_backend.py @@ -1,6 +1,7 @@ # Copyright (c) 2016 Ansible, Inc. # All Rights Reserved. +import json import logging import requests @@ -37,6 +38,15 @@ class WebhookBackend(AWXBaseEmailBackend): super(WebhookBackend, self).__init__(fail_silently=fail_silently) def format_body(self, body): + # If `body` has body field, attempt to use this as the main body, + # otherwise, leave it as a sub-field + if isinstance(body, dict) and 'body' in body and isinstance(body['body'], str): + try: + potential_body = json.loads(body['body']) + if isinstance(potential_body, dict): + body = potential_body + except json.JSONDecodeError: + pass return body def send_messages(self, messages):