diff --git a/moto/ses/exceptions.py b/moto/ses/exceptions.py index d3e60aef..46564af1 100644 --- a/moto/ses/exceptions.py +++ b/moto/ses/exceptions.py @@ -36,6 +36,29 @@ class TemplateNameAlreadyExists(RESTError): ) +class ValidationError(RESTError): + code = 400 + + def __init__(self, message): + super(ValidationError, self).__init__("ValidationError", message) + + +class InvalidParameterValue(RESTError): + code = 400 + + def __init__(self, message): + super(InvalidParameterValue, self).__init__("InvalidParameterValue", message) + + +class InvalidRenderingParameterException: + code = 400 + + def __init__(self, message): + super(InvalidRenderingParameterException, self).__init__( + "InvalidRenderingParameterException", message + ) + + class TemplateDoesNotExist(RESTError): code = 400 diff --git a/moto/ses/models.py b/moto/ses/models.py index d9a44a37..138c33f3 100644 --- a/moto/ses/models.py +++ b/moto/ses/models.py @@ -1,8 +1,12 @@ from __future__ import unicode_literals -import datetime +import json import email +import datetime +from email.mime.base import MIMEBase from email.utils import parseaddr +from email.mime.multipart import MIMEMultipart +from email.encoders import encode_7or8bit from moto.core import BaseBackend, BaseModel from moto.sns.models import sns_backends @@ -11,6 +15,9 @@ from .exceptions import ( ConfigurationSetDoesNotExist, EventDestinationAlreadyExists, TemplateNameAlreadyExists, + ValidationError, + InvalidParameterValue, + InvalidRenderingParameterException, TemplateDoesNotExist, RuleSetNameAlreadyExists, RuleSetDoesNotExist, @@ -288,8 +295,36 @@ class SESBackend(BaseBackend): def add_template(self, template_info): template_name = template_info["template_name"] + if not template_name: + raise ValidationError( + "1 validation error detected: " + "Value null at 'template.templateName'" + "failed to satisfy constraint: Member must not be null" + ) + if self.templates.get(template_name, None): raise TemplateNameAlreadyExists("Duplicate Template Name.") + + template_subject = template_info["subject_part"] + if not template_subject: + raise InvalidParameterValue("The subject must be specified.") + self.templates[template_name] = template_info + + def update_template(self, template_info): + template_name = template_info["template_name"] + if not template_name: + raise ValidationError( + "1 validation error detected: " + "Value null at 'template.templateName'" + "failed to satisfy constraint: Member must not be null" + ) + + if not self.templates.get(template_name, None): + raise TemplateDoesNotExist("Invalid Template Name.") + + template_subject = template_info["subject_part"] + if not template_subject: + raise InvalidParameterValue("The subject must be specified.") self.templates[template_name] = template_info def get_template(self, template_name): @@ -300,6 +335,50 @@ class SESBackend(BaseBackend): def list_templates(self): return list(self.templates.values()) + def render_template(self, render_data): + template_name = render_data.get("name", "") + template = self.templates.get(template_name, None) + if not template: + raise TemplateDoesNotExist("Invalid Template Name.") + + template_data = render_data.get("data") + try: + template_data = json.loads(template_data) + except ValueError: + raise InvalidRenderingParameterException( + "Template rendering data is invalid" + ) + + subject_part = template["subject_part"] + text_part = template["text_part"] + html_part = template["html_part"] + + for key, value in template_data.items(): + subject_part = str.replace(str(subject_part), "{{%s}}" % key, value) + text_part = str.replace(str(text_part), "{{%s}}" % key, value) + html_part = str.replace(str(html_part), "{{%s}}" % key, value) + + email = MIMEMultipart("alternative") + + mime_text = MIMEBase("text", "plain;charset=UTF-8") + mime_text.set_payload(text_part.encode("utf-8")) + encode_7or8bit(mime_text) + email.attach(mime_text) + + mime_html = MIMEBase("text", "html;charset=UTF-8") + mime_html.set_payload(html_part.encode("utf-8")) + encode_7or8bit(mime_html) + email.attach(mime_html) + + now = datetime.datetime.now().isoformat() + + rendered_template = "Date: %s\r\nSubject: %s\r\n%s" % ( + now, + subject_part, + email.as_string(), + ) + return rendered_template + def create_receipt_rule_set(self, rule_set_name): if self.receipt_rule_set.get(rule_set_name) is not None: raise RuleSetNameAlreadyExists("Duplicate receipt rule set Name.") diff --git a/moto/ses/responses.py b/moto/ses/responses.py index 93bf5f4f..61a6c565 100644 --- a/moto/ses/responses.py +++ b/moto/ses/responses.py @@ -179,15 +179,27 @@ class EmailResponse(BaseResponse): def create_template(self): template_data = self._get_dict_param("Template") template_info = {} - template_info["text_part"] = template_data["._text_part"] - template_info["html_part"] = template_data["._html_part"] - template_info["template_name"] = template_data["._name"] - template_info["subject_part"] = template_data["._subject_part"] + template_info["text_part"] = template_data.get("._text_part", "") + template_info["html_part"] = template_data.get("._html_part", "") + template_info["template_name"] = template_data.get("._name", "") + template_info["subject_part"] = template_data.get("._subject_part", "") template_info["Timestamp"] = datetime.utcnow() ses_backend.add_template(template_info=template_info) template = self.response_template(CREATE_TEMPLATE) return template.render() + def update_template(self): + template_data = self._get_dict_param("Template") + template_info = {} + template_info["text_part"] = template_data.get("._text_part", "") + template_info["html_part"] = template_data.get("._html_part", "") + template_info["template_name"] = template_data.get("._name", "") + template_info["subject_part"] = template_data.get("._subject_part", "") + template_info["Timestamp"] = datetime.utcnow() + ses_backend.update_template(template_info=template_info) + template = self.response_template(UPDATE_TEMPLATE) + return template.render() + def get_template(self): template_name = self._get_param("TemplateName") template_data = ses_backend.get_template(template_name) @@ -199,6 +211,12 @@ class EmailResponse(BaseResponse): template = self.response_template(LIST_TEMPLATES) return template.render(templates=email_templates) + def test_render_template(self): + render_info = self._get_dict_param("Template") + rendered_template = ses_backend.render_template(render_info) + template = self.response_template(RENDER_TEMPLATE) + return template.render(template=rendered_template) + def create_receipt_rule_set(self): rule_set_name = self._get_param("RuleSetName") ses_backend.create_receipt_rule_set(rule_set_name) @@ -369,6 +387,13 @@ CREATE_TEMPLATE = """ + + + 47e0ef1a-9bf2-11e1-9279-0100e8cf12ba + +""" + GET_TEMPLATE = """