Skip to content

Commit

Permalink
Merge pull request #12 from carpentries/feature/10-update-after-testing
Browse files Browse the repository at this point in the history
Update after testing
  • Loading branch information
pbanaszkiewicz authored Apr 15, 2024
2 parents 610f546 + 5e280c2 commit ad33513
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 219 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ required.

## First steps (Python)

This project is for Python 3.10 version.
This project is for Python 3.11 version.

To work on Python code you should install [Poetry](https://python-poetry.org/docs/#installation).

Expand Down
2 changes: 1 addition & 1 deletion cdk/lib/lambda-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class LambdaStack extends Stack {
this.lambdaFunction = new PythonFunction(this, 'EmailWorker', {
functionName: 'amy-email-worker',
architecture: Architecture.X86_64, // more expensive than ARM
runtime: Runtime.PYTHON_3_10,
runtime: Runtime.PYTHON_3_11,
entry: '../worker',
index: 'main.py',
handler: 'handler',
Expand Down
323 changes: 176 additions & 147 deletions cdk/package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions cdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
"devDependencies": {
"@types/jest": "^29.2.3",
"@types/node": "18.11.9",
"aws-cdk": "^2.100.0",
"aws-cdk": "^2.137.0",
"ts-node": "^10.9.1",
"typescript": "~4.9.3"
},
"dependencies": {
"@aws-cdk/aws-lambda-python-alpha": "^2.82.0-alpha.0",
"aws-cdk-lib": "^2.54.0",
"@aws-cdk/aws-lambda-python-alpha": "^2.137.0-alpha.0",
"aws-cdk-lib": "^2.137.0",
"constructs": "^10.0.0",
"source-map-support": "^0.5.21"
}
Expand Down
2 changes: 1 addition & 1 deletion worker/.python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10
3.11
4 changes: 2 additions & 2 deletions worker/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "MIT"
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
python = "^3.11"
boto3 = "^1.26.146"
aws-lambda-powertools = {extras = ["aws-sdk"], version = "^2.16.1"}
psycopg = {extras = ["binary"], version = "^3.1.9"}
Expand All @@ -27,7 +27,7 @@ pytest-asyncio = "^0.23.2"
flake8-pyproject = "^1.2.3"

[tool.mypy]
python_version = "3.10"
python_version = "3.11"
strict = true

[tool.isort]
Expand Down
24 changes: 16 additions & 8 deletions worker/src/handler.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import json
import logging
from typing import cast
from uuid import UUID

import httpx
from jinja2 import DebugUndefined, Environment
from jinja2.exceptions import TemplateSyntaxError
from pydantic_core import ValidationError

from src.api import ScheduledEmailController, UriError, context_entry, fetch_model_field
from src.email import render_email, send_email
Expand All @@ -13,6 +14,7 @@
ContextModel,
MailgunCredentials,
ScheduledEmail,
SinglePropertyLinkModel,
ToHeaderModel,
WorkerOutputEmail,
)
Expand Down Expand Up @@ -40,27 +42,33 @@ async def handle_email(
client: httpx.AsyncClient,
token_cache: TokenCache,
) -> WorkerOutputEmail:
id = email.id
id = email.pk
logger.info(f"Working on email {id}.")

locked_email = await controller.lock_by_id(id)
logger.info(f"Locked email {id}.")

try:
context = ContextModel(json.loads(locked_email.context_json))
except json.JSONDecodeError as exc:
context = ContextModel(locked_email.context_json)
except ValidationError as exc:
logger.error(f"Validation error: {exc}")
return await return_fail_email(
id,
f"Failed to read JSON from email context {id}. Error: {exc}",
f"Failed to read email context {id}.",
controller,
)

try:
recipients = ToHeaderModel(root=json.loads(locked_email.to_header_context_json))
except json.JSONDecodeError as exc:
recipients = ToHeaderModel(
root=cast(
list[SinglePropertyLinkModel], locked_email.to_header_context_json
)
)
except ValidationError as exc:
logger.error(f"Validation error: {exc}")
return await return_fail_email(
id,
f"Failed to read JSON from email recipients {id}. Error: {exc}",
f"Failed to read email recipients {id}.",
controller,
)

Expand Down
8 changes: 4 additions & 4 deletions worker/src/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,23 @@ class ScheduledEmailStatus(Enum):


class ScheduledEmail(BaseModel):
id: UUID
pk: UUID
created_at: datetime
last_updated_at: Optional[datetime]
state: ScheduledEmailStatus
scheduled_at: datetime
to_header: list[str]

# JSON, e.g. '[{"api_uri": "api:person#1", "property": "email"}]'
to_header_context_json: str
to_header_context_json: list[dict[str, Any]]
from_header: str
reply_to_header: str
cc_header: list[str]
bcc_header: list[str]
subject: str
body: str
context_json: str # JSON, e.g. '{"name": "John Doe"}'
template_id: UUID
context_json: dict[str, Any] # JSON, e.g. '{"name": "John Doe"}'
template: str # template name


class RenderedScheduledEmail(ScheduledEmail):
Expand Down
8 changes: 4 additions & 4 deletions worker/tests/test_api_scheduledemailcontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
def scheduled_email_fixture() -> dict[str, Any]:
now = datetime.now(tz=timezone.utc)
return {
"id": uuid4(),
"pk": uuid4(),
"created_at": now,
"last_updated_at": now,
"state": "scheduled",
"scheduled_at": now,
"to_header": ["[email protected]"],
"to_header_context_json": '[{"api_uri": "api:person#1", "property": "email"}]',
"to_header_context_json": [{"api_uri": "api:person#1", "property": "email"}],
"from_header": "[email protected]",
"reply_to_header": "",
"cc_header": [],
"bcc_header": [],
"subject": "Sample email",
"body": "Hello, {{ name }}!",
"context_json": '{"name": "John"}',
"template_id": uuid4(),
"context_json": {"name": "John"},
"template": "Welcome email",
}


Expand Down
32 changes: 16 additions & 16 deletions worker/tests/test_email.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime
from datetime import UTC, datetime
from typing import Any
from unittest.mock import AsyncMock
from uuid import uuid4
Expand Down Expand Up @@ -57,23 +57,23 @@ def test_render_email() -> None:
# Arrange
engine = Environment(autoescape=True, undefined=DebugUndefined)
id_ = uuid4()
now_ = datetime.utcnow()
now_ = datetime.now(tz=UTC)
email = ScheduledEmail(
id=id_,
pk=id_,
created_at=now_,
last_updated_at=now_,
state=ScheduledEmailStatus.SCHEDULED,
scheduled_at=now_,
to_header=[],
to_header_context_json="[]",
to_header_context_json=[],
from_header="",
reply_to_header="",
cc_header=[],
bcc_header=[],
subject="Hello World and {{ name }}!",
body="Welcome, {{ name }}!",
context_json="{}",
template_id=id_,
context_json={},
template="Welcome email",
)
context = {"name": "John Doe"}
recipients = ["[email protected]", ""] # empty string should be filtered out
Expand All @@ -95,15 +95,15 @@ async def test_send_email() -> None:
# Arrange
client = AsyncMock()
id_ = uuid4()
now_ = datetime.utcnow()
now_ = datetime.now(tz=UTC)
email = RenderedScheduledEmail(
id=id_,
pk=id_,
created_at=now_,
last_updated_at=now_,
state=ScheduledEmailStatus.SCHEDULED,
scheduled_at=now_,
to_header=[],
to_header_context_json="[]",
to_header_context_json=[],
to_header_rendered=["[email protected]"],
from_header="",
reply_to_header="",
Expand All @@ -113,8 +113,8 @@ async def test_send_email() -> None:
subject_rendered="Hello World and John Doe!",
body="Welcome, {{ name }}!",
body_rendered="Welcome, John Doe!",
context_json="{}",
template_id=id_,
context_json={},
template="Welcome email",
)
credentials = MailgunCredentials(
MAILGUN_SENDER_DOMAIN="example.com",
Expand Down Expand Up @@ -146,15 +146,15 @@ async def test_send_email__outgoing_addresses_overwritten() -> None:
# Arrange
client = AsyncMock()
id_ = uuid4()
now_ = datetime.utcnow()
now_ = datetime.now(tz=UTC)
email = RenderedScheduledEmail(
id=id_,
pk=id_,
created_at=now_,
last_updated_at=now_,
state=ScheduledEmailStatus.SCHEDULED,
scheduled_at=now_,
to_header=["[email protected]"],
to_header_context_json="[]",
to_header_context_json=[],
to_header_rendered=["[email protected]"],
from_header="[email protected]",
reply_to_header="[email protected]",
Expand All @@ -164,8 +164,8 @@ async def test_send_email__outgoing_addresses_overwritten() -> None:
subject_rendered="Hello World and John Doe!",
body="Welcome, {{ name }}!",
body_rendered="Welcome, John Doe!",
context_json="{}",
template_id=id_,
context_json={},
template="Welcome email",
)
credentials = MailgunCredentials(
MAILGUN_SENDER_DOMAIN="example.com",
Expand Down
Loading

0 comments on commit ad33513

Please sign in to comment.