Skip to content

Commit

Permalink
44 create routers for internal and public routes (#48)
Browse files Browse the repository at this point in the history
* Created a create_mailer() function in the mailer.py

* Created internal/public routers

* linting
  • Loading branch information
jcadam14 authored Nov 20, 2024
1 parent 9818f4b commit 1e55993
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 86 deletions.
70 changes: 6 additions & 64 deletions src/regtech_mail_api/api.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
from fastapi import FastAPI, Request
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import OAuth2AuthorizationCodeBearer

from regtech_mail_api.mailer import Mailer, MockMailer, SmtpMailer
from regtech_mail_api.models import Email
from regtech_mail_api.settings import EmailApiSettings, EmailMailerType, kc_settings
from regtech_mail_api.settings import kc_settings
from regtech_mail_api.public import router as public_router
from regtech_mail_api.internal import router as internal_router

from starlette.authentication import requires
from starlette.middleware.authentication import AuthenticationMiddleware

from regtech_api_commons.api.router_wrapper import Router
from regtech_api_commons.oauth2.oauth2_backend import BearerTokenAuthBackend
from regtech_api_commons.oauth2.oauth2_admin import OAuth2Admin

Expand All @@ -33,61 +31,5 @@
allow_headers=["*"],
)

router = Router()

# FIXME: Come up with a better way of handling these settings
# without having to do all the `type: ignore`s
settings = EmailApiSettings() # type: ignore
mailer: Mailer

match settings.email_mailer:
case EmailMailerType.SMTP:
mailer = SmtpMailer(
settings.smtp_host, # type: ignore
settings.smtp_port,
settings.smtp_username.get_secret_value() if settings.smtp_username else None, # type: ignore
settings.smtp_password.get_secret_value() if settings.smtp_password else None, # type: ignore
settings.smtp_use_tls,
)
case EmailMailerType.MOCK:
mailer = MockMailer()
case _:
raise ValueError(f"Mailer type {settings.email_mailer} not supported")


@router.get("/welcome")
@requires("authenticated")
def read_root(request: Request):
return {"message": "Welcome to the Email API"}


@router.post("/send")
@requires("authenticated")
async def send_email(request: Request):
sender_addr = request.user.email
sender_name = request.user.name if request.user.name else ""
type = request.headers["case-type"]

header = "[BETA]"
if "cfpb" in sender_addr.lower().split("@")[-1]:
header = "[CFPB BETA]"
if settings.environment:
header = f"[{settings.environment}]"

subject = f"{header} SBL User Request for {type}"

form_data = await request.form()

body_lines = [f"{k}: {v}" for k, v in form_data.items()]
email_body = f"Contact Email: {sender_addr}\n"
email_body += f"Contact Name: {sender_name}\n\n"
email_body += "\n".join(body_lines)

email = Email(subject, email_body, settings.from_addr, to={settings.to})

mailer.send(email)

return {"email": email}


app.include_router(router)
app.include_router(internal_router, prefix="/internal")
app.include_router(public_router, prefix="/public")
21 changes: 21 additions & 0 deletions src/regtech_mail_api/internal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from fastapi import Request

from regtech_api_commons.api.router_wrapper import Router

from regtech_mail_api.settings import EmailApiSettings
from regtech_mail_api.models import Email
from regtech_mail_api.mailer import create_mailer

settings = EmailApiSettings()

router = Router()


@router.post("/confirmation/send")
async def send_email(request: Request):
mailer = create_mailer()
# build email
to_list = ["contact email", "signer email"]
email = Email("Subject", "Body", settings.from_addr, to=to_list)
mailer.send(email)
return "Called internal send"
22 changes: 22 additions & 0 deletions src/regtech_mail_api/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import ssl

from regtech_mail_api.models import Email
from regtech_mail_api.settings import EmailApiSettings, EmailMailerType


class Mailer(ABC):
Expand Down Expand Up @@ -44,3 +45,24 @@ def send(self, message: Email) -> None:
print("--- Message Start ---")
print(message.to_email_message())
print("--- Message End ---")


def create_mailer():
settings = EmailApiSettings() # type: ignore
mailer: Mailer

match settings.email_mailer:
case EmailMailerType.SMTP:
mailer = SmtpMailer(
settings.smtp_host, # type: ignore
settings.smtp_port,
settings.smtp_username.get_secret_value() if settings.smtp_username else None, # type: ignore
settings.smtp_password.get_secret_value() if settings.smtp_password else None, # type: ignore
settings.smtp_use_tls,
)
case EmailMailerType.MOCK:
mailer = MockMailer()
case _:
raise ValueError(f"Mailer type {settings.email_mailer} not supported")

return mailer
41 changes: 41 additions & 0 deletions src/regtech_mail_api/public.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from fastapi import Request
from starlette.authentication import requires

from regtech_api_commons.api.router_wrapper import Router

from regtech_mail_api.settings import EmailApiSettings
from regtech_mail_api.models import Email
from regtech_mail_api.mailer import create_mailer

settings = EmailApiSettings()

router = Router()


@router.post("/case/send")
@requires("authenticated")
async def send_email(request: Request):
sender_addr = request.user.email
sender_name = request.user.name if request.user.name else ""
type = request.headers["case-type"]

header = "[BETA]"
if "cfpb" in sender_addr.lower().split("@")[-1]:
header = "[CFPB BETA]"
if settings.environment:
header = f"[{settings.environment}]"

subject = f"{header} SBL User Request for {type}"

form_data = await request.form()

body_lines = [f"{k}: {v}" for k, v in form_data.items()]
email_body = f"Contact Email: {sender_addr}\n"
email_body += f"Contact Name: {sender_name}\n\n"
email_body += "\n".join(body_lines)

email = Email(subject, email_body, settings.from_addr, to={settings.to})

create_mailer().send(email)

return {"email": email}
36 changes: 17 additions & 19 deletions tests/test_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,31 @@ class TestEmailApiAuthentication:
def test_unauthed_endpoints(
self, mocker: MockerFixture, app_fixture: FastAPI, unauthed_user_mock: Mock
):
client = TestClient(app_fixture)
res = client.get("/welcome")
assert res.status_code == 403

client = TestClient(app_fixture)
res = client.post(
"/send",
"/public/case/send",
json={"data": "data"},
)
assert res.status_code == 403

res = client.post("/internal/confirmation/send")
assert res.status_code == 200

def test_authed_endpoints(
self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock
):
email_json = {
"email": {
"subject": "Institution Profile Change",
"body": "lei: 1234567890ABCDEFGHIJ\ninstitution_name_1: Fintech 1\ntin_1: 12-3456789\nrssd_1: 1234567",
"from_addr": "[email protected]",
"to": ["[email protected]"],
"cc": None,
"bcc": None,
}
}

mock = mocker.patch("regtech_mail_api.api.send_email")
mock.return_value = {"email": email_json}
client = TestClient(app_fixture)
res = client.get("/welcome")
res = client.post(
"/public/case/send",
headers={
"case-type": "Institution Profile Change",
},
data={
"lei": "1234567890ABCDEFGHIJ",
"institution_name_1": "Fintech 1",
"tin_1": "12-3456789",
"rssd_1": "1234567",
},
)
client = TestClient(app_fixture)
assert res.status_code == 200
14 changes: 11 additions & 3 deletions tests/test_send.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def test_send_no_profile(

client = TestClient(app_fixture)
res = client.post(
"/send",
"/public/case/send",
headers={
"case-type": "Institution Profile Change",
},
Expand All @@ -82,7 +82,7 @@ def test_send_no_profile(
assert res.status_code == 200
assert res.json() == email_json

def test_send(
def test_case_send(
self, mocker: MockerFixture, app_fixture: FastAPI, full_user_mock: Mock
):
email_json = {
Expand All @@ -98,7 +98,7 @@ def test_send(

client = TestClient(app_fixture)
res = client.post(
"/send",
"/public/case/send",
headers={
"case-type": "Institution Profile Change",
},
Expand All @@ -111,3 +111,11 @@ def test_send(
)
assert res.status_code == 200
assert res.json() == email_json

def test_confirmation_send(
self, mocker: MockerFixture, app_fixture: FastAPI, full_user_mock: Mock
):
client = TestClient(app_fixture)
res = client.post("/internal/confirmation/send")
assert res.status_code == 200
assert res.json() == "Called internal send"

0 comments on commit 1e55993

Please sign in to comment.