generated from ghga-de/microservice-repository-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add HTML email template string to config (gsi 19) (#3)
* Update dependency for event Add notifier port * Implement basic template and a test * Remove unused mypy error suppressor * Fix type hinting on _construct_email() * Add plaintext email template Silence mypy errors --------- Co-authored-by: Byron Himes <[email protected]>
- Loading branch information
1 parent
eeaccb6
commit 3855120
Showing
10 changed files
with
207 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,19 @@ | ||
html_email_template: '<!DOCTYPE html><html><head></head><body style="color: #00393f;padding: | ||
12px;"><h2>Dear $recipient_name,</h2><p>$plaintext_body</p><p>Warm regards,</p><h3>The | ||
GHGA Team</h3></body></html>' | ||
kafka_servers: | ||
- kafka:9092 | ||
notification_event_topic: notifications | ||
notification_event_type: notification | ||
plaintext_email_template: 'Dear $recipient_name, | ||
$plaintext_body | ||
Warm regards, | ||
The GHGA Team' | ||
service_instance_id: '1' | ||
service_name: ns |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# Copyright 2021 - 2023 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln | ||
# for the German Human Genome-Phenome Archive (GHGA) | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
"""Contains the concrete implementation of a NotifierPort""" | ||
|
||
from email.message import EmailMessage | ||
from string import Template | ||
|
||
from ghga_event_schemas import pydantic_ as event_schemas | ||
|
||
from ns.config import Config | ||
from ns.ports.inbound.notifier import NotifierPort | ||
|
||
|
||
class Notifier(NotifierPort): | ||
"""Implementation of the Notifier Port""" | ||
|
||
def __init__(self, *, config: Config): | ||
"""Initialize the Notifier with configured host, port, and so on""" | ||
self._config = config | ||
|
||
async def send_notification(self, *, notification: event_schemas.Notification): | ||
"""Sends notifications based on the channel info provided (e.g. email addresses)""" | ||
raise NotImplementedError | ||
|
||
def _construct_email( | ||
self, *, notification: event_schemas.Notification | ||
) -> EmailMessage: | ||
"""Constructs an EmailMessage object from the contents of an email notification event""" | ||
message = EmailMessage() | ||
message["To"] = notification.recipient_email | ||
message["Cc"] = notification.email_cc | ||
message["Bcc"] = notification.email_bcc | ||
message["Subject"] = notification.subject | ||
|
||
payload_as_dict = notification.dict() | ||
|
||
# create plaintext html with template | ||
plaintext_template = Template(self._config.plaintext_email_template) | ||
try: | ||
plaintext_email = plaintext_template.substitute(payload_as_dict) | ||
except KeyError as err: | ||
raise self.VariableNotSuppliedError(variable=err.args[0]) from err | ||
except ValueError as err: | ||
raise self.BadTemplateFormat(problem=err.args[0]) from err | ||
|
||
message.set_content(plaintext_email) | ||
|
||
# create html version of email, replacing variables of $var format | ||
html_template = Template(self._config.html_email_template) | ||
|
||
try: | ||
html_email = html_template.substitute(payload_as_dict) | ||
except KeyError as err: | ||
raise self.VariableNotSuppliedError(variable=err.args[0]) from err | ||
except ValueError as err: | ||
raise self.BadTemplateFormat(problem=err.args[0]) from err | ||
|
||
# add the html version to the EmailMessage object | ||
message.add_alternative(html_email, subtype="html") | ||
|
||
return message |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Copyright 2021 - 2023 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln | ||
# for the German Human Genome-Phenome Archive (GHGA) | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
"""Contains a port for the notifier""" | ||
from abc import ABC, abstractmethod | ||
|
||
from ghga_event_schemas import pydantic_ as event_schemas | ||
|
||
|
||
class NotifierPort(ABC): | ||
"""Describes a notifier service in basic detail""" | ||
|
||
class VariableNotSuppliedError(KeyError): | ||
"""Raised when an html template contains a variable that isn't supplied""" | ||
|
||
def __init__(self, *, variable: str): | ||
message = f"Nothing supplied for template variable {variable}" | ||
super().__init__(message) | ||
|
||
class BadTemplateFormat(ValueError): | ||
"""Raised when the html template contains improperly formatted content""" | ||
|
||
def __init__(self, *, problem: str): | ||
message = f"Problem with HTML template: {problem}" | ||
super().__init__(message) | ||
|
||
@abstractmethod | ||
async def send_notification(self, *, notification: event_schemas.Notification): | ||
"""Sends out notifications based on the event details""" | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,22 +13,68 @@ | |
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Test dummy.""" | ||
"""Test basic event consumption""" | ||
import pytest | ||
from ghga_event_schemas import pydantic_ as event_schemas | ||
from hexkit.providers.akafka.testutils import kafka_fixture # noqa: F401 | ||
|
||
from ns.core.notifier import Notifier | ||
from tests.fixtures.config import get_config | ||
from tests.fixtures.joint import JointFixture, joint_fixture # noqa: F401 | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_basic_consume(joint_fixture: JointFixture): # noqa: F811 | ||
"""Verify that the consumer runs the dummy _send_email() and raises the error.""" | ||
async def test_basic_path(joint_fixture: JointFixture): # noqa: F811 | ||
"""Verify that the event is correctly translated into a basic email object""" | ||
await joint_fixture.kafka.publish_event( | ||
payload={"key": "value"}, | ||
payload={ | ||
"recipient_email": "[email protected]", | ||
"email_cc": [], | ||
"email_bcc": [], | ||
"subject": "Test123", | ||
"recipient_name": "Yolanda Martinez", | ||
"plaintext_body": "Where are you, where are you, Yolanda?", | ||
}, | ||
type_=joint_fixture.config.notification_event_type, | ||
topic=joint_fixture.config.notification_event_topic, | ||
) | ||
|
||
event_subscriber = await joint_fixture.container.kafka_event_subscriber() | ||
with pytest.raises(NotImplementedError): | ||
await event_subscriber.run(forever=False) | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_email_construction(): | ||
"""Verify that the email is getting constructed properly from the template.""" | ||
notification = event_schemas.Notification( | ||
recipient_email="[email protected]", | ||
email_cc=[], | ||
email_bcc=[], | ||
subject="Test123", | ||
recipient_name="Yolanda Martinez", | ||
plaintext_body="Where are you, where are you, Yolanda?", | ||
) | ||
|
||
notifier = Notifier(config=get_config()) | ||
msg = notifier._construct_email( | ||
notification=notification | ||
) # pylint: disable=protected-access | ||
|
||
assert msg is not None | ||
|
||
plaintext_body = msg.get_body(preferencelist=("plain")) | ||
assert plaintext_body is not None | ||
|
||
plaintext_content = plaintext_body.get_content() # type: ignore[attr-defined] | ||
expected_plaintext = "Dear Yolanda Martinez,\n\nWhere are you, where are you, Yolanda?\n\nWarm regards,\n\nThe GHGA Team" | ||
assert plaintext_content.strip() == expected_plaintext | ||
|
||
html_body = msg.get_body(preferencelist=("html")) | ||
assert html_body is not None | ||
|
||
html_content = html_body.get_content() # type: ignore[attr-defined] | ||
assert html_content is not None | ||
|
||
expected_html = '<!DOCTYPE html><html><head></head><body style="color: #00393f;padding: 12px;"><h2>Dear Yolanda Martinez,</h2><p>Where are you, where are you, Yolanda?</p><p>Warm regards,</p><h3>The GHGA Team</h3></body></html>' | ||
assert html_content.strip() == expected_html |