mirror of
https://github.com/ansible/awx.git
synced 2024-10-30 22:21:13 +03:00
save/validate messages
This commit is contained in:
parent
3bb0aa4eec
commit
13b9679496
@ -4160,6 +4160,43 @@ class NotificationTemplateSerializer(BaseSerializer):
|
||||
d['recent_notifications'] = self._recent_notifications(obj)
|
||||
return d
|
||||
|
||||
def validate_messages(self, messages):
|
||||
if messages is None:
|
||||
return None
|
||||
|
||||
error_list = []
|
||||
collected_messages = []
|
||||
|
||||
# Validate structure / content types
|
||||
if not isinstance(messages, dict):
|
||||
error_list.append(_("Expected dict for 'messages' field, found {}".format(type(messages))))
|
||||
else:
|
||||
for event in messages:
|
||||
if event not in ['started', 'success', 'error']:
|
||||
error_list.append(_("Event '{}' invalid, must be one of 'started', 'success', or 'error'").format(event))
|
||||
continue
|
||||
event_messages = messages[event]
|
||||
if event_messages is None:
|
||||
continue
|
||||
if not isinstance(event_messages, dict):
|
||||
error_list.append(_("Expected dict for event '{}', found {}").format(event, type(event_messages)))
|
||||
continue
|
||||
for message_type in event_messages:
|
||||
if message_type not in ['message', 'body']:
|
||||
error_list.append(_("Message type '{}' invalid, must be either 'message' or 'body'").format(message_type))
|
||||
continue
|
||||
message = event_messages[message_type]
|
||||
if message is None:
|
||||
continue
|
||||
if not isinstance(message, str):
|
||||
error_list.append(_("Expected string for '{}', found {}, ").format(message_type, type(message)))
|
||||
continue
|
||||
if message_type == 'message':
|
||||
if '\n' in message:
|
||||
error_list.append(_("Messages cannot contain newlines (found newline in {} event)".format(event)))
|
||||
continue
|
||||
collected_messages.append(message)
|
||||
|
||||
def validate(self, attrs):
|
||||
from awx.api.views import NotificationTemplateDetail
|
||||
|
||||
|
@ -84,6 +84,26 @@ class NotificationTemplate(CommonModelNameNotUnique):
|
||||
def save(self, *args, **kwargs):
|
||||
new_instance = not bool(self.pk)
|
||||
update_fields = kwargs.get('update_fields', [])
|
||||
|
||||
# preserve existing notification messages if not overwritten by new messages
|
||||
if not new_instance:
|
||||
old_nt = NotificationTemplate.objects.get(pk=self.id)
|
||||
old_messages = old_nt.messages
|
||||
new_messages = self.messages
|
||||
|
||||
if old_messages is not None:
|
||||
for event in ['started', 'success', 'error']:
|
||||
if not new_messages.get(event, {}) and old_messages.get(event, {}):
|
||||
new_messages[event] = old_messages[event]
|
||||
continue
|
||||
if new_messages.get(event, {}) and old_messages.get(event, {}):
|
||||
old_event_msgs = old_messages[event]
|
||||
new_event_msgs = new_messages[event]
|
||||
for msg_type in ['message', 'body']:
|
||||
if msg_type not in new_event_msgs and old_event_msgs.get(msg_type, None):
|
||||
new_event_msgs[msg_type] = old_event_msgs[msg_type]
|
||||
new_messages.setdefault(event, None)
|
||||
|
||||
for field in filter(lambda x: self.notification_class.init_parameters[x]['type'] == "password",
|
||||
self.notification_class.init_parameters):
|
||||
if self.notification_configuration[field].startswith("$encrypted$"):
|
||||
|
@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
# AWX
|
||||
from awx.api.serializers import NotificationTemplateSerializer
|
||||
|
||||
|
||||
class StubNotificationTemplate():
|
||||
notification_type = 'email'
|
||||
|
||||
|
||||
class TestNotificationTemplateSerializer():
|
||||
|
||||
@pytest.mark.parametrize('valid_messages',
|
||||
[None,
|
||||
{'started': None},
|
||||
{'started': {'message': None}},
|
||||
{'started': {'message': 'valid'}},
|
||||
{'started': {'body': 'valid'}},
|
||||
{'started': {'message': 'valid', 'body': 'valid'}},
|
||||
{'started': None, 'success': None, 'error': None},
|
||||
{'started': {'message': None, 'body': None},
|
||||
'success': {'message': None, 'body': None},
|
||||
'error': {'message': None, 'body': None}},
|
||||
{'started': {'message': '{{ job.id }}', 'body': '{{ job.status }}'},
|
||||
'success': {'message': None, 'body': '{{ job_friendly_name }}'},
|
||||
'error': {'message': '{{ url }}', 'body': None}},
|
||||
{'started': {'body': '{{ job_summary_dict }}'}},
|
||||
{'started': {'body': '{{ job.summary_fields.inventory.total_hosts }}'}},
|
||||
{'started': {'body': u'Iñtërnâtiônàlizætiøn'}}
|
||||
])
|
||||
def test_valid_messages(self, valid_messages):
|
||||
serializer = NotificationTemplateSerializer()
|
||||
serializer.instance = StubNotificationTemplate()
|
||||
serializer.validate_messages(valid_messages)
|
||||
|
||||
@pytest.mark.parametrize('invalid_messages',
|
||||
[1,
|
||||
[],
|
||||
'',
|
||||
{'invalid_event': ''},
|
||||
{'started': 'should_be_dict'},
|
||||
{'started': {'bad_message_type': ''}},
|
||||
{'started': {'message': 1}},
|
||||
{'started': {'message': []}},
|
||||
{'started': {'message': {}}},
|
||||
{'started': {'message': '{{ unclosed_braces'}},
|
||||
{'started': {'message': '{{ undefined }}'}},
|
||||
{'started': {'message': '{{ job.undefined }}'}},
|
||||
{'started': {'message': '{{ job.id | bad_filter }}'}},
|
||||
{'started': {'message': '{{ job.__class__ }}'}},
|
||||
{'started': {'message': 'Newlines \n not allowed\n'}},
|
||||
])
|
||||
def test_invalid__messages(self, invalid_messages):
|
||||
serializer = NotificationTemplateSerializer()
|
||||
serializer.instance = StubNotificationTemplate()
|
||||
with pytest.raises(ValidationError):
|
||||
serializer.validate_messages(invalid_messages)
|
Loading…
Reference in New Issue
Block a user