From fce4dde2e369e0555c569580dd14f5970660b579 Mon Sep 17 00:00:00 2001 From: David Glick Date: Wed, 2 Oct 2024 11:56:39 -0700 Subject: [PATCH] get email template from registry --- .../volto/formsupport/browser/configure.zcml | 12 - .../formsupport/browser/send_mail_template.pt | 38 --- .../browser/send_mail_template_table.pt | 57 ----- .../volto/formsupport/interfaces.py | 21 ++ .../volto/formsupport/processors/email.py | 55 ++--- .../formsupport/profiles/default/metadata.xml | 2 +- .../profiles/default/registry/main.xml | 3 +- .../volto/formsupport/upgrades.zcml | 8 + .../tests/functional/test_email_processor.py | 229 ++++++------------ backend/tests/functional/test_event.py | 4 +- backend/tests/setup/test_setup_install.py | 2 +- 11 files changed, 131 insertions(+), 300 deletions(-) delete mode 100644 backend/src/collective/volto/formsupport/browser/send_mail_template.pt delete mode 100644 backend/src/collective/volto/formsupport/browser/send_mail_template_table.pt diff --git a/backend/src/collective/volto/formsupport/browser/configure.zcml b/backend/src/collective/volto/formsupport/browser/configure.zcml index 4c2dff84..b24c5daa 100644 --- a/backend/src/collective/volto/formsupport/browser/configure.zcml +++ b/backend/src/collective/volto/formsupport/browser/configure.zcml @@ -22,18 +22,6 @@ type="plone" /> - - -
- -
-
    - -
  • - label: - ${value} -
  • -
    -
-
- - -

- A new form has been submitted from - url -

-
-
- diff --git a/backend/src/collective/volto/formsupport/browser/send_mail_template_table.pt b/backend/src/collective/volto/formsupport/browser/send_mail_template_table.pt deleted file mode 100644 index fc5fd2b7..00000000 --- a/backend/src/collective/volto/formsupport/browser/send_mail_template_table.pt +++ /dev/null @@ -1,57 +0,0 @@ - - -
- - - Form submission data for ${title} - -
- - - - - - - - - - - - - - - -
FieldValue
${label}${value}
-
- -
-
diff --git a/backend/src/collective/volto/formsupport/interfaces.py b/backend/src/collective/volto/formsupport/interfaces.py index 0bf5e6d4..084c9228 100644 --- a/backend/src/collective/volto/formsupport/interfaces.py +++ b/backend/src/collective/volto/formsupport/interfaces.py @@ -2,6 +2,7 @@ from zope.interface import Attribute from zope.interface import Interface from zope.publisher.interfaces.browser import IDefaultBrowserLayer +from zope import schema from ZPublisher.BaseRequest import BaseRequest import dataclasses @@ -95,3 +96,23 @@ def __init__(context: FormSubmissionContext): def __call__(): """Process the data.""" + + +DEFAULT_TEMPLATE = """ +${mail_header} +
+${form_fields} +
+${mail_footer} +""" + +class IFormSettings(Interface): + + mail_templates = schema.Dict( + title="Email templates", + key_type=schema.TextLine(), + value_type=schema.Text(), + default={ + "default": DEFAULT_TEMPLATE + } + ) diff --git a/backend/src/collective/volto/formsupport/processors/email.py b/backend/src/collective/volto/formsupport/processors/email.py index 5968bc4b..bf5c48f2 100644 --- a/backend/src/collective/volto/formsupport/processors/email.py +++ b/backend/src/collective/volto/formsupport/processors/email.py @@ -130,9 +130,16 @@ def get_subject(self): subject = self.substitute_variables(subject) return subject - def substitute_variables(self, value): + def substitute_variables(self, value, context=None): + if context is None: + context = self.form_data + + def replace(match): + name = match.group(1) + return context.get(name, "") + pattern = r"\$\{([^}]+)\}" - return re.sub(pattern, lambda match: self.get_value(match.group(1), ""), value) + return re.sub(pattern, replace, value) def get_value(self, field_id, default=None): return self.form_data.get(field_id, default) @@ -148,36 +155,22 @@ def get_confirmation_recipients(self) -> str: return confirmation_recipients def prepare_message(self): - mail_header = self.block.get("mail_header", {}).get("data", "") - mail_footer = self.block.get("mail_footer", {}).get("data", "") - - # Check if there is content - mail_header = BeautifulSoup(mail_header).get_text() if mail_header else None - mail_footer = BeautifulSoup(mail_footer).get_text() if mail_footer else None - - # TODO - email_format_page_template_mapping = { - "list": "send_mail_template", - "table": "send_mail_template_table", - } - email_format = self.block.get("email_format", "") - template_name = email_format_page_template_mapping.get( - email_format, "send_mail_template" - ) - - message_template = api.content.get_view( - name=template_name, - context=self.context, - request=self.request, - ) - parameters = { - "parameters": self.records, - "url": self.context.absolute_url(), - "title": self.context.Title(), - "mail_header": mail_header, - "mail_footer": mail_footer, + templates = api.portal.get_registry_record("schemaform.mail_templates") + template_name = self.block.get("email_template", "default") + template = templates[template_name] + template_vars = { + "mail_header": self.block.get("mail_header", {}).get("data", ""), + "mail_footer": self.block.get("mail_footer", {}).get("data", ""), } - return message_template(**parameters) + form_fields = "\n" + for record in self.records: + value = str(record["value"]) + template_vars[record["field_id"]] = value + form_fields += f"" + form_fields += "\n
{record['label']}{value}
\n" + template_vars["form_fields"] = form_fields + message = self.substitute_variables(template, template_vars) + return message def add_attachments(self, msg): if not self.attachments: diff --git a/backend/src/collective/volto/formsupport/profiles/default/metadata.xml b/backend/src/collective/volto/formsupport/profiles/default/metadata.xml index 7ef9ea68..7048ae61 100644 --- a/backend/src/collective/volto/formsupport/profiles/default/metadata.xml +++ b/backend/src/collective/volto/formsupport/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 1300 + 1400 profile-plone.restapi:default profile-plone.volto:default diff --git a/backend/src/collective/volto/formsupport/profiles/default/registry/main.xml b/backend/src/collective/volto/formsupport/profiles/default/registry/main.xml index b6314fd3..f8b8abbd 100644 --- a/backend/src/collective/volto/formsupport/profiles/default/registry/main.xml +++ b/backend/src/collective/volto/formsupport/profiles/default/registry/main.xml @@ -3,6 +3,7 @@ i18n:domain="collective.volto.formsupport" > - + diff --git a/backend/src/collective/volto/formsupport/upgrades.zcml b/backend/src/collective/volto/formsupport/upgrades.zcml index 5943a3f0..9656d07f 100644 --- a/backend/src/collective/volto/formsupport/upgrades.zcml +++ b/backend/src/collective/volto/formsupport/upgrades.zcml @@ -32,4 +32,12 @@ handler=".upgrades.to_1300" /> + + diff --git a/backend/tests/functional/test_email_processor.py b/backend/tests/functional/test_email_processor.py index f9f2ff62..f1d81089 100644 --- a/backend/tests/functional/test_email_processor.py +++ b/backend/tests/functional/test_email_processor.py @@ -1,12 +1,10 @@ -from collective.volto.formsupport.utils import generate_email_token -from email.parser import Parser from pathlib import Path import base64 +import email import pytest import re import transaction -import xml.etree.ElementTree as ET @pytest.fixture @@ -137,12 +135,12 @@ def test_email_sent_with_fallback_subject_and_sender(self, submit_form): assert response.status_code == 200 assert res["data"] == {"xxx": "bar"} - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "Subject: Form Submission" in msg - assert "From: Plone test site " in msg - assert "To: site_addr@plone.com" in msg - assert "Reply-To: Plone test site " in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + assert msg["Subject"] == "Form Submission" + assert msg["From"] == "Plone test site " + assert msg["To"] == "site_addr@plone.com" + assert msg["Reply-To"] == "Plone test site " def test_email_sent_with_only_fields_from_schema(self, submit_form): self.document.blocks = { @@ -181,14 +179,15 @@ def test_email_sent_with_only_fields_from_schema(self, submit_form): assert response.status_code == 200 assert res["data"] == {"xxx": "foo"} - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "Subject: test subject" in msg - assert "From: Plone test site " in msg - assert "To: site_addr@plone.com" in msg - assert "Reply-To: John Doe " in msg - assert "foo: foo" in msg - assert "bar: bar" not in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + body = msg.get_body().get_content() + assert msg["Subject"] == "test subject" + assert msg["From"] == "Plone test site " + assert msg["To"] == "site_addr@plone.com" + assert msg["Reply-To"] == "John Doe " + assert "foofoo" in body + assert "barbar" not in body def test_email_sent_with_site_recipient(self, submit_form): self.document.blocks = { @@ -223,14 +222,15 @@ def test_email_sent_with_site_recipient(self, submit_form): ) transaction.commit() assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "Subject: test subject" in msg - assert "From: Plone test site " in msg - assert "To: site_addr@plone.com" in msg - assert "Reply-To: Plone test site " in msg - assert "Message: just want to say hi" in msg - assert "Name: John" in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + body = msg.get_body().get_content() + assert msg["Subject"] == "test subject" + assert msg["From"] == "Plone test site " + assert msg["To"] == "site_addr@plone.com" + assert msg["Reply-To"] == "Plone test site " + assert "Messagejust want to say hi" in body + assert "NameJohn" in body def test_email_sent_with_forwarded_headers(self, submit_form): self.document.blocks = { @@ -269,14 +269,15 @@ def test_email_sent_with_forwarded_headers(self, submit_form): ) transaction.commit() assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "Subject: test subject" in msg - assert "From: Plone test site " in msg - assert "To: site_addr@plone.com" in msg - assert "Reply-To: Plone test site " in msg - assert "Message: just want to say hi" in msg - assert "Name: John" in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + body = msg.get_body().get_content() + assert msg["Subject"] == "test subject" + assert msg["From"] == "Plone test site " + assert msg["To"] == "site_addr@plone.com" + assert msg["Reply-To"] == "Plone test site " + assert "Messagejust want to say hi" in body + assert "NameJohn" in body assert "REMOTE_ADDR" in msg assert "PATH_INFO" in msg @@ -315,14 +316,15 @@ def test_email_sent_with_block_recipient_if_set(self, submit_form): ) transaction.commit() assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "Subject: test subject" in msg - assert "From: Plone test site " in msg - assert "To: to@block.com" in msg - assert "Reply-To: Plone test site " in msg - assert "Message: just want to say hi" in msg - assert "Name: John" in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + body = msg.get_body().get_content() + assert msg["Subject"] == "test subject" + assert msg["From"] == "Plone test site " + assert msg["To"] == "to@block.com" + assert msg["Reply-To"] == "Plone test site " + assert "Messagejust want to say hi" in body + assert "NameJohn" in body def test_email_sent_with_subject_from_form_data(self, submit_form): self.document.blocks = { @@ -358,14 +360,15 @@ def test_email_sent_with_subject_from_form_data(self, submit_form): transaction.commit() assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "Subject: just want to say hi" in msg - assert "From: Plone test site " in msg - assert "To: site_addr@plone.com" in msg - assert "Reply-To: Plone test site " in msg - assert "Message: just want to say hi" in msg - assert "Name: John" in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + body = msg.get_body().get_content() + assert msg["Subject"] == "just want to say hi" + assert msg["From"] == "Plone test site " + assert msg["To"] == "site_addr@plone.com" + assert msg["Reply-To"] == "Plone test site " + assert "Messagejust want to say hi" in body + assert "NameJohn" in body def test_email_with_sender_from_form_data(self, submit_form): self.document.blocks = { @@ -408,13 +411,14 @@ def test_email_with_sender_from_form_data(self, submit_form): transaction.commit() assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "From: Plone test site " in msg - assert "To: site_addr@plone.com" in msg - assert "Reply-To: Smith " in msg - assert "Message: just want to say hi" in msg - assert "Name: Smith" in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + body = msg.get_body().get_content() + assert msg["From"] == "Plone test site " + assert msg["To"] == "site_addr@plone.com" + assert msg["Reply-To"] == "Smith " + assert "Messagejust want to say hi" in body + assert "NameSmith" in body def test_email_with_bcc_from_form_data(self, submit_form): self.document.blocks = { @@ -457,12 +461,12 @@ def test_email_with_bcc_from_form_data(self, submit_form): assert response.status_code == 200 assert len(self.mailhost.messages) == 2 - msg = self.mailhost.messages[0].decode("utf-8") - assert "\nTo: site_addr@plone.com" in msg - assert "\nTo: smith@doe.com" not in msg - bcc_msg = self.mailhost.messages[1].decode("utf-8") - assert "\nTo: site_addr@plone.com" not in bcc_msg - assert "\nTo: smith@doe.com" in bcc_msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + assert msg["To"] == "site_addr@plone.com" + bcc_msg = self.mailhost.messages[1] + msg = email.message_from_bytes(bcc_msg, policy=email.policy.default) + assert msg["To"] == "smith@doe.com" def test_send_attachment(self, submit_form, file_str): self.document.blocks = { @@ -590,98 +594,9 @@ def test_send_confirmation(self, submit_form): transaction.commit() assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - parsed_msg = Parser().parsestr(msg) - msg = re.sub(r"\s+", " ", msg) - assert parsed_msg.get("from") == "Plone test site " - assert parsed_msg.get("to") == "smith@doe.com" - assert parsed_msg.get("subject") == "Form Submission" - assert "Name: Smith" in msg - - def test_email_body_formatted_as_table(self, submit_form): - self.document.blocks = { - "form-id": { - "@type": "schemaForm", - "send": True, - "email_format": "table", - "schema": { - "fieldsets": [ - { - "id": "default", - "title": "Default", - "fields": ["message", "name"], - }, - ], - "properties": { - "message": {"title": "Message"}, - "name": {"title": "Name"}, - }, - "required": [], - }, - }, - } - transaction.commit() - - response = submit_form( - url=self.document_url, - data={ - "data": {"message": "just want to say hi", "name": "John"}, - "block_id": "form-id", - }, - ) - transaction.commit() - assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg).replace(" >", ">") - - assert """""" in msg - assert "
" in msg - assert ( - f"Form submission data for {self.document.title}" in msg - ) - assert """Field""" in msg - assert """Value""" in msg - - assert """Name""" in msg - - assert f'John' in msg - assert """""" in msg - assert f'just want to say hi' in msg - - def test_email_body_formatted_as_list(self, submit_form): - self.document.blocks = { - "form-id": { - "@type": "schemaForm", - "send": True, - "email_format": "list", - "schema": { - "fieldsets": [ - { - "id": "default", - "title": "Default", - "fields": ["message", "name"], - }, - ], - "properties": { - "message": {"title": "Message"}, - "name": {"title": "Name"}, - }, - "required": [], - }, - }, - } - transaction.commit() - - response = submit_form( - url=self.document_url, - data={ - "data": {"message": "just want to say hi", "name": "John"}, - "block_id": "form-id", - }, - ) - transaction.commit() - assert response.status_code == 200 - msg = self.mailhost.messages[0].decode("utf-8") - msg = re.sub(r"\s+", " ", msg) - assert "Message: just want to say hi" in msg - assert "Name: John" in msg + msg = self.mailhost.messages[0] + msg = email.message_from_bytes(msg, policy=email.policy.default) + assert msg["From"] == "Plone test site " + assert msg["To"] == "smith@doe.com" + assert msg["Subject"] == "Form Submission" + assert "NameSmith" in msg.get_body().get_content() diff --git a/backend/tests/functional/test_event.py b/backend/tests/functional/test_event.py index 9dc4f4ae..0caab058 100644 --- a/backend/tests/functional/test_event.py +++ b/backend/tests/functional/test_event.py @@ -52,5 +52,5 @@ def test_trigger_event(self, submit_form): msg = re.sub(r"\s+", " ", msg) assert "To: site_addr@plone.com" in msg assert "To: smith@doe.com" not in msg - assert "Message: just want to say hi" in msg - assert "Reply: hello" in msg + assert "Messagejust want to say hi" in msg + assert "ReplyHello" in msg diff --git a/backend/tests/setup/test_setup_install.py b/backend/tests/setup/test_setup_install.py index a2f2a207..666326ef 100644 --- a/backend/tests/setup/test_setup_install.py +++ b/backend/tests/setup/test_setup_install.py @@ -16,4 +16,4 @@ def test_browserlayer(self, browser_layers): def test_latest_version(self, profile_last_version): """Test latest version of default profile.""" - assert profile_last_version(f"{PACKAGE_NAME}:default") == "1300" + assert profile_last_version(f"{PACKAGE_NAME}:default") == "1400"