oncall-engine/engine/apps/api/serializers/custom_button.py
Michael Derynck 3582f9b08f
Improve Jinja Template feedback and error handling (#884)
* Improve feedback so template errors are given to user

* Add security error logging

* Add limits for templates, payloads, results

* Show popup error notification for webhook errors and template errors that don't have a result

* Update tests

* Split exceptions into warnings/errors to give more control when previewing, rendering, saving templates

* Limit title lengths

* Make TypeError a warning

* Adjust title length limit

* Remove length limiting on urlize since it is being done on template render

* Fix tests

* Add KeyError and ValueError to warnings

* No longer enforcing json result when saving webhook in case it is dependent on payload

* Add tests for expected exceptions coming from apply_jinja_template

* Update changelog

* Send raw post if template result is not JSON
2022-11-28 09:46:51 -07:00

67 lines
2.4 KiB
Python

from collections import defaultdict
from django.core.validators import URLValidator, ValidationError
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from apps.alerts.models import CustomButton
from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField
from common.api_helpers.utils import CurrentOrganizationDefault, CurrentTeamDefault
from common.jinja_templater import apply_jinja_template
from common.jinja_templater.apply_jinja_template import JinjaTemplateError, JinjaTemplateWarning
class CustomButtonSerializer(serializers.ModelSerializer):
id = serializers.CharField(read_only=True, source="public_primary_key")
organization = serializers.HiddenField(default=CurrentOrganizationDefault())
team = TeamPrimaryKeyRelatedField(allow_null=True, default=CurrentTeamDefault())
forward_whole_payload = serializers.BooleanField(allow_null=True, required=False)
class Meta:
model = CustomButton
fields = [
"id",
"name",
"team",
"webhook",
"data",
"user",
"password",
"authorization_header",
"organization",
"forward_whole_payload",
]
extra_kwargs = {
"name": {"required": True, "allow_null": False, "allow_blank": False},
"webhook": {"required": True, "allow_null": False, "allow_blank": False},
}
validators = [UniqueTogetherValidator(queryset=CustomButton.objects.all(), fields=["name", "organization"])]
def validate_webhook(self, webhook):
if webhook:
try:
URLValidator()(webhook)
except ValidationError:
raise serializers.ValidationError("Webhook is incorrect")
return webhook
return None
def validate_data(self, data):
if not data:
return None
try:
apply_jinja_template(data, alert_payload=defaultdict(str), alert_group_id="abcd")
except JinjaTemplateError as e:
raise serializers.ValidationError(e.fallback_message)
except JinjaTemplateWarning:
# Suppress render exceptions since we do not have a representative payload to test with
pass
return data
def validate_forward_whole_payload(self, data):
if data is None:
return False
return data