Functionality added to SES service (#3670)
* correct exceptions when mising parameters * test_render_template function * update ses template function * fix import * except fixed * tests and py2 fix
This commit is contained in:
parent
4a01360d88
commit
c72670d536
@ -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):
|
class TemplateDoesNotExist(RESTError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
import json
|
||||||
import email
|
import email
|
||||||
|
import datetime
|
||||||
|
from email.mime.base import MIMEBase
|
||||||
from email.utils import parseaddr
|
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.core import BaseBackend, BaseModel
|
||||||
from moto.sns.models import sns_backends
|
from moto.sns.models import sns_backends
|
||||||
@ -11,6 +15,9 @@ from .exceptions import (
|
|||||||
ConfigurationSetDoesNotExist,
|
ConfigurationSetDoesNotExist,
|
||||||
EventDestinationAlreadyExists,
|
EventDestinationAlreadyExists,
|
||||||
TemplateNameAlreadyExists,
|
TemplateNameAlreadyExists,
|
||||||
|
ValidationError,
|
||||||
|
InvalidParameterValue,
|
||||||
|
InvalidRenderingParameterException,
|
||||||
TemplateDoesNotExist,
|
TemplateDoesNotExist,
|
||||||
RuleSetNameAlreadyExists,
|
RuleSetNameAlreadyExists,
|
||||||
RuleSetDoesNotExist,
|
RuleSetDoesNotExist,
|
||||||
@ -288,8 +295,36 @@ class SESBackend(BaseBackend):
|
|||||||
|
|
||||||
def add_template(self, template_info):
|
def add_template(self, template_info):
|
||||||
template_name = template_info["template_name"]
|
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):
|
if self.templates.get(template_name, None):
|
||||||
raise TemplateNameAlreadyExists("Duplicate Template Name.")
|
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
|
self.templates[template_name] = template_info
|
||||||
|
|
||||||
def get_template(self, template_name):
|
def get_template(self, template_name):
|
||||||
@ -300,6 +335,50 @@ class SESBackend(BaseBackend):
|
|||||||
def list_templates(self):
|
def list_templates(self):
|
||||||
return list(self.templates.values())
|
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):
|
def create_receipt_rule_set(self, rule_set_name):
|
||||||
if self.receipt_rule_set.get(rule_set_name) is not None:
|
if self.receipt_rule_set.get(rule_set_name) is not None:
|
||||||
raise RuleSetNameAlreadyExists("Duplicate receipt rule set Name.")
|
raise RuleSetNameAlreadyExists("Duplicate receipt rule set Name.")
|
||||||
|
@ -179,15 +179,27 @@ class EmailResponse(BaseResponse):
|
|||||||
def create_template(self):
|
def create_template(self):
|
||||||
template_data = self._get_dict_param("Template")
|
template_data = self._get_dict_param("Template")
|
||||||
template_info = {}
|
template_info = {}
|
||||||
template_info["text_part"] = template_data["._text_part"]
|
template_info["text_part"] = template_data.get("._text_part", "")
|
||||||
template_info["html_part"] = template_data["._html_part"]
|
template_info["html_part"] = template_data.get("._html_part", "")
|
||||||
template_info["template_name"] = template_data["._name"]
|
template_info["template_name"] = template_data.get("._name", "")
|
||||||
template_info["subject_part"] = template_data["._subject_part"]
|
template_info["subject_part"] = template_data.get("._subject_part", "")
|
||||||
template_info["Timestamp"] = datetime.utcnow()
|
template_info["Timestamp"] = datetime.utcnow()
|
||||||
ses_backend.add_template(template_info=template_info)
|
ses_backend.add_template(template_info=template_info)
|
||||||
template = self.response_template(CREATE_TEMPLATE)
|
template = self.response_template(CREATE_TEMPLATE)
|
||||||
return template.render()
|
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):
|
def get_template(self):
|
||||||
template_name = self._get_param("TemplateName")
|
template_name = self._get_param("TemplateName")
|
||||||
template_data = ses_backend.get_template(template_name)
|
template_data = ses_backend.get_template(template_name)
|
||||||
@ -199,6 +211,12 @@ class EmailResponse(BaseResponse):
|
|||||||
template = self.response_template(LIST_TEMPLATES)
|
template = self.response_template(LIST_TEMPLATES)
|
||||||
return template.render(templates=email_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):
|
def create_receipt_rule_set(self):
|
||||||
rule_set_name = self._get_param("RuleSetName")
|
rule_set_name = self._get_param("RuleSetName")
|
||||||
ses_backend.create_receipt_rule_set(rule_set_name)
|
ses_backend.create_receipt_rule_set(rule_set_name)
|
||||||
@ -369,6 +387,13 @@ CREATE_TEMPLATE = """<CreateTemplateResponse xmlns="http://ses.amazonaws.com/doc
|
|||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</CreateTemplateResponse>"""
|
</CreateTemplateResponse>"""
|
||||||
|
|
||||||
|
UPDATE_TEMPLATE = """<UpdateTemplateResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||||
|
<UpdateTemplateResult/>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf12ba</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</UpdateTemplateResponse>"""
|
||||||
|
|
||||||
GET_TEMPLATE = """<GetTemplateResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
GET_TEMPLATE = """<GetTemplateResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||||
<GetTemplateResult>
|
<GetTemplateResult>
|
||||||
<Template>
|
<Template>
|
||||||
@ -383,6 +408,7 @@ GET_TEMPLATE = """<GetTemplateResponse xmlns="http://ses.amazonaws.com/doc/2010-
|
|||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</GetTemplateResponse>"""
|
</GetTemplateResponse>"""
|
||||||
|
|
||||||
|
|
||||||
LIST_TEMPLATES = """<ListTemplatesResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
LIST_TEMPLATES = """<ListTemplatesResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||||
<ListTemplatesResult>
|
<ListTemplatesResult>
|
||||||
<TemplatesMetadata>
|
<TemplatesMetadata>
|
||||||
@ -399,6 +425,19 @@ LIST_TEMPLATES = """<ListTemplatesResponse xmlns="http://ses.amazonaws.com/doc/2
|
|||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ListTemplatesResponse>"""
|
</ListTemplatesResponse>"""
|
||||||
|
|
||||||
|
RENDER_TEMPLATE = """
|
||||||
|
<TestRenderTemplateResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||||
|
<TestRenderTemplateResult>
|
||||||
|
<RenderedTemplate>
|
||||||
|
{{template | e}}
|
||||||
|
</RenderedTemplate>
|
||||||
|
</TestRenderTemplateResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf12ba</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</TestRenderTemplateResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
CREATE_RECEIPT_RULE_SET = """<CreateReceiptRuleSetResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
CREATE_RECEIPT_RULE_SET = """<CreateReceiptRuleSetResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||||
<CreateReceiptRuleSetResult/>
|
<CreateReceiptRuleSetResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import json
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError
|
||||||
@ -484,3 +485,67 @@ def test_create_ses_template():
|
|||||||
|
|
||||||
result = conn.list_templates()
|
result = conn.list_templates()
|
||||||
result["TemplatesMetadata"][0]["Name"].should.equal("MyTemplate")
|
result["TemplatesMetadata"][0]["Name"].should.equal("MyTemplate")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ses
|
||||||
|
def test_render_template():
|
||||||
|
conn = boto3.client("ses", region_name="us-east-1")
|
||||||
|
|
||||||
|
kwargs = dict(
|
||||||
|
TemplateName="MyTestTemplate",
|
||||||
|
TemplateData=json.dumps({"name": "John", "favoriteanimal": "Lion"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
conn.test_render_template(**kwargs)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("TemplateDoesNotExist")
|
||||||
|
|
||||||
|
conn.create_template(
|
||||||
|
Template={
|
||||||
|
"TemplateName": "MyTestTemplate",
|
||||||
|
"SubjectPart": "Greetings, {{name}}!",
|
||||||
|
"TextPart": "Dear {{name}},"
|
||||||
|
"\r\nYour favorite animal is {{favoriteanimal}}.",
|
||||||
|
"HtmlPart": "<h1>Hello {{name}},"
|
||||||
|
"</h1><p>Your favorite animal is {{favoriteanimal}}.</p>",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
result = conn.test_render_template(**kwargs)
|
||||||
|
result["RenderedTemplate"].should.contain("Subject: Greetings, John!")
|
||||||
|
result["RenderedTemplate"].should.contain("Dear John,")
|
||||||
|
result["RenderedTemplate"].should.contain("<h1>Hello John,</h1>")
|
||||||
|
result["RenderedTemplate"].should.contain("Your favorite animal is Lion")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ses
|
||||||
|
def test_update_ses_template():
|
||||||
|
conn = boto3.client("ses", region_name="us-east-1")
|
||||||
|
template = {
|
||||||
|
"TemplateName": "MyTemplateToUpdate",
|
||||||
|
"SubjectPart": "Greetings, {{name}}!",
|
||||||
|
"TextPart": "Dear {{name}}," "\r\nYour favorite animal is {{favoriteanimal}}.",
|
||||||
|
"HtmlPart": "<h1>Hello {{name}},"
|
||||||
|
"</h1><p>Your favorite animal is {{favoriteanimal}}.</p>",
|
||||||
|
}
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
conn.update_template(Template=template)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("TemplateDoesNotExist")
|
||||||
|
|
||||||
|
conn.create_template(Template=template)
|
||||||
|
|
||||||
|
template["SubjectPart"] = "Hi, {{name}}!"
|
||||||
|
template["TextPart"] = "Dear {{name}},\r\n Your favorite color is {{color}}"
|
||||||
|
template[
|
||||||
|
"HtmlPart"
|
||||||
|
] = "<h1>Hello {{name}},</h1><p>Your favorite color is {{color}}</p>"
|
||||||
|
conn.update_template(Template=template)
|
||||||
|
|
||||||
|
result = conn.get_template(TemplateName=template["TemplateName"])
|
||||||
|
result["Template"]["SubjectPart"].should.equal("Hi, {{name}}!")
|
||||||
|
result["Template"]["TextPart"].should.equal(
|
||||||
|
"Dear {{name}},\n Your favorite color is {{color}}"
|
||||||
|
)
|
||||||
|
result["Template"]["HtmlPart"].should.equal(
|
||||||
|
"<h1>Hello {{name}},</h1><p>Your favorite color is {{color}}</p>"
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user