Add Mailer class method to email TOs to MSFT
This commit is contained in:
parent
baf7be2961
commit
00a5a98577
@ -241,6 +241,7 @@ To generate coverage reports for the Javascript tests:
|
|||||||
- `MAIL_SENDER`: String. Email address to send outgoing mail from.
|
- `MAIL_SENDER`: String. Email address to send outgoing mail from.
|
||||||
- `MAIL_SERVER`: The SMTP host
|
- `MAIL_SERVER`: The SMTP host
|
||||||
- `MAIL_TLS`: Boolean. Use TLS to connect to the SMTP server.
|
- `MAIL_TLS`: Boolean. Use TLS to connect to the SMTP server.
|
||||||
|
- `MICROSOFT_TASK_ORDER_EMAIL_ADDRESS`: String. Email address for Microsoft to receive PDFs of new and updated task orders.
|
||||||
- `PERMANENT_SESSION_LIFETIME`: Integer specifying how many seconds a user's session can stay valid for. https://flask.palletsprojects.com/en/1.1.x/config/#PERMANENT_SESSION_LIFETIME
|
- `PERMANENT_SESSION_LIFETIME`: Integer specifying how many seconds a user's session can stay valid for. https://flask.palletsprojects.com/en/1.1.x/config/#PERMANENT_SESSION_LIFETIME
|
||||||
- `PGDATABASE`: String specifying the name of the postgres database.
|
- `PGDATABASE`: String specifying the name of the postgres database.
|
||||||
- `PGHOST`: String specifying the hostname of the postgres database.
|
- `PGHOST`: String specifying the hostname of the postgres database.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
import smtplib
|
import smtplib
|
||||||
|
import io
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
|
|
||||||
|
|
||||||
@ -76,8 +77,34 @@ class Mailer(object):
|
|||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def send(self, recipients, subject, body):
|
def _add_attachment(self, message, content, filename, maintype, subtype):
|
||||||
|
with io.BytesIO(content) as bytes_:
|
||||||
|
message.add_attachment(
|
||||||
|
bytes_.read(), filename=filename, maintype=maintype, subtype=subtype
|
||||||
|
)
|
||||||
|
|
||||||
|
def send(self, recipients, subject, body, attachments=[]):
|
||||||
|
"""
|
||||||
|
Send a message, optionally with attachments.
|
||||||
|
Attachments should be provided as a list of dictionaries of the form:
|
||||||
|
{
|
||||||
|
content: bytes,
|
||||||
|
maintype: string,
|
||||||
|
subtype: string,
|
||||||
|
filename: string,
|
||||||
|
}
|
||||||
|
"""
|
||||||
message = self._build_message(recipients, subject, body)
|
message = self._build_message(recipients, subject, body)
|
||||||
|
if attachments:
|
||||||
|
message.make_mixed()
|
||||||
|
for attachment in attachments:
|
||||||
|
self._add_attachment(
|
||||||
|
message,
|
||||||
|
content=attachment["content"],
|
||||||
|
filename=attachment["filename"],
|
||||||
|
maintype=attachment.get("maintype", "application"),
|
||||||
|
subtype=attachment.get("subtype", "octet-stream"),
|
||||||
|
)
|
||||||
self.connection.send(message)
|
self.connection.send(message)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -26,6 +26,7 @@ MAIL_PORT
|
|||||||
MAIL_SENDER
|
MAIL_SENDER
|
||||||
MAIL_SERVER
|
MAIL_SERVER
|
||||||
MAIL_TLS
|
MAIL_TLS
|
||||||
|
MICROSOFT_TASK_ORDER_EMAIL_ADDRESS = example@example.com
|
||||||
PERMANENT_SESSION_LIFETIME = 1800
|
PERMANENT_SESSION_LIFETIME = 1800
|
||||||
PGDATABASE = atat
|
PGDATABASE = atat
|
||||||
PGHOST = localhost
|
PGHOST = localhost
|
||||||
|
@ -164,6 +164,12 @@ def pdf_upload2():
|
|||||||
yield FileStorage(fp, content_type="application/pdf")
|
yield FileStorage(fp, content_type="application/pdf")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def downloaded_task_order():
|
||||||
|
with open(PDF_FILENAME, "rb") as fp:
|
||||||
|
yield {"name": "mock.pdf", "content": fp.read()}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def extended_financial_verification_data(pdf_upload):
|
def extended_financial_verification_data(pdf_upload):
|
||||||
return {
|
return {
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from atst.utils.mailer import Mailer, Mailer, MailConnection, RedisConnection
|
from atst.utils.mailer import (
|
||||||
|
Mailer,
|
||||||
|
MailConnection,
|
||||||
|
RedisConnection,
|
||||||
|
)
|
||||||
|
from atst.utils.localization import translate
|
||||||
|
from email.mime.base import MIMEBase
|
||||||
|
|
||||||
|
|
||||||
class MockConnection(MailConnection):
|
class MockConnection(MailConnection):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._messages = []
|
self._messages = []
|
||||||
|
self.sender = "mock@mock.com"
|
||||||
|
|
||||||
def send(self, message):
|
def send(self, message):
|
||||||
self._messages.append(message)
|
self._messages.append(message)
|
||||||
@ -46,3 +53,55 @@ def test_redis_mailer_can_save_messages(app):
|
|||||||
assert message_data["recipients"][0] in message
|
assert message_data["recipients"][0] in message
|
||||||
assert message_data["subject"] in message
|
assert message_data["subject"] in message
|
||||||
assert message_data["body"] in message
|
assert message_data["body"] in message
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_with_attachment(app, mailer, downloaded_task_order):
|
||||||
|
to_number = "11111111111111"
|
||||||
|
attachment = {
|
||||||
|
"maintype": "application",
|
||||||
|
"subtype": "pdf",
|
||||||
|
"filename": downloaded_task_order["name"],
|
||||||
|
"content": downloaded_task_order["content"],
|
||||||
|
}
|
||||||
|
mailer.send(
|
||||||
|
recipients=[app.config["MICROSOFT_TASK_ORDER_EMAIL_ADDRESS"]],
|
||||||
|
subject=translate("email.task_order_sent.subject", {"to_number": to_number}),
|
||||||
|
body=translate("email.task_order_sent.body", {"to_number": to_number}),
|
||||||
|
attachments=[attachment],
|
||||||
|
)
|
||||||
|
# one email was sent
|
||||||
|
assert len(mailer.messages) == 1
|
||||||
|
|
||||||
|
# the email was sent to Microsoft with the correct subject line
|
||||||
|
message = mailer.messages[0]
|
||||||
|
assert message["To"] == app.config["MICROSOFT_TASK_ORDER_EMAIL_ADDRESS"]
|
||||||
|
assert message["Subject"] == translate(
|
||||||
|
"email.task_order_sent.subject", {"to_number": to_number}
|
||||||
|
)
|
||||||
|
|
||||||
|
# the email was sent as a multipart message with two parts -- the message
|
||||||
|
# body and the attachment
|
||||||
|
assert message.is_multipart()
|
||||||
|
message_payload = message.get_payload()
|
||||||
|
assert len(message_payload) == 2
|
||||||
|
|
||||||
|
# A body and attachment were in the email
|
||||||
|
body = next(
|
||||||
|
(
|
||||||
|
part
|
||||||
|
for part in message_payload
|
||||||
|
if part["Content-Type"] == 'text/plain; charset="utf-8"'
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
attachment = next(
|
||||||
|
(part for part in message_payload if part["Content-Type"] == "application/pdf"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
assert body
|
||||||
|
assert attachment
|
||||||
|
|
||||||
|
assert (
|
||||||
|
attachment["Content-Disposition"]
|
||||||
|
== f"attachment; filename=\"{downloaded_task_order['name']}\""
|
||||||
|
)
|
||||||
|
@ -84,6 +84,9 @@ email:
|
|||||||
application_invite: "{inviter_name} has invited you to a JEDI cloud application"
|
application_invite: "{inviter_name} has invited you to a JEDI cloud application"
|
||||||
portfolio_invite: "{inviter_name} has invited you to a JEDI cloud portfolio"
|
portfolio_invite: "{inviter_name} has invited you to a JEDI cloud portfolio"
|
||||||
environment_ready: JEDI cloud environment ready
|
environment_ready: JEDI cloud environment ready
|
||||||
|
task_order_sent:
|
||||||
|
subject: "Task Order {to_number}"
|
||||||
|
body: "Task Order number {to_number} updated."
|
||||||
empty_state:
|
empty_state:
|
||||||
applications:
|
applications:
|
||||||
header:
|
header:
|
||||||
@ -480,7 +483,6 @@ portfolios:
|
|||||||
"False": View Team
|
"False": View Team
|
||||||
"True": Edit Team
|
"True": Edit Team
|
||||||
perms_env_mgmt:
|
perms_env_mgmt:
|
||||||
|
|
||||||
"False": View Environments
|
"False": View Environments
|
||||||
"True": Edit Environments
|
"True": Edit Environments
|
||||||
roles:
|
roles:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user