Skip to content

Commit 628042c

Browse files
refactor: decouple models
1 parent a657d3e commit 628042c

File tree

10 files changed

+128
-65
lines changed

10 files changed

+128
-65
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from typing import Literal
2+
3+
from pydantic import EmailStr
4+
5+
from .notifications import Event
6+
7+
8+
class AccountRequestedEvent(Event):
9+
type: Literal["account.requested"] = "account.requested"
10+
11+
first_name: str
12+
last_name: str
13+
email: EmailStr
14+
15+
# TODO: add more fields as needed

packages/models-library/src/models_library/rpc/notifications/messages.py

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from typing import Annotated, Literal, TypeAlias
2+
3+
from pydantic import BaseModel, ConfigDict, EmailStr, Field
4+
5+
6+
class Event(BaseModel):
7+
type: str
8+
9+
model_config = ConfigDict(
10+
frozen=True,
11+
)
12+
13+
14+
class EmailChannel(BaseModel):
15+
type: Literal["email"] = "email"
16+
17+
to: EmailStr
18+
reply_to: EmailStr | None = None
19+
20+
21+
class SMSChannel(BaseModel):
22+
type: Literal["sms"] = "sms"
23+
24+
phone_number: str # Consider using phone number validation library here
25+
26+
27+
Channel: TypeAlias = EmailChannel | SMSChannel
28+
29+
30+
class Notification(BaseModel):
31+
event: Event
32+
channel: Annotated[Channel, Field(discriminator="type")]

packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/notifications/messages.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
from models_library.api_schemas_notifications import NOTIFICATIONS_RPC_NAMESPACE
44
from models_library.rabbitmq_basic_types import RPCMethodName
5-
from models_library.rpc.notifications.messages import NotificationMessage
5+
from models_library.rpc.notifications.notifications import Notification
66
from pydantic import NonNegativeInt, TypeAdapter
77

88
from ... import RabbitMQRPCClient
99

1010
_DEFAULT_TIMEOUT_S: Final[NonNegativeInt] = 30
1111

1212

13-
async def send_notification_message(
13+
async def send_notification(
1414
rabbitmq_rpc_client: RabbitMQRPCClient,
1515
*,
16-
message: NotificationMessage,
16+
notification: Notification,
1717
) -> None:
1818
await rabbitmq_rpc_client.request(
1919
NOTIFICATIONS_RPC_NAMESPACE,
20-
TypeAdapter(RPCMethodName).validate_python("send_notification_message"),
20+
TypeAdapter(RPCMethodName).validate_python("send_notification"),
2121
timeout_s=_DEFAULT_TIMEOUT_S,
22-
message=message,
22+
notification=notification,
2323
)
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from models_library.rpc.notifications.messages import NotificationMessage
1+
from models_library.rpc.notifications.notifications import Notification
22
from servicelib.celery.task_manager import TaskManager
33
from servicelib.rabbitmq import RPCRouter
44

@@ -8,12 +8,12 @@
88

99

1010
@router.expose(reraise_if_error_type=())
11-
async def send_notification_message(
11+
async def send_notification(
1212
task_manager: TaskManager,
1313
*,
14-
message: NotificationMessage,
14+
notification: Notification,
1515
) -> None:
16-
await notifications_service.send_notification_message(
16+
await notifications_service.send_notification(
1717
task_manager,
18-
message=message,
18+
notification=notification,
1919
)

services/notifications/src/simcore_service_notifications/clients/celery.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
from celery_library.types import register_celery_types, register_pydantic_types
77
from fastapi import FastAPI
88
from fastapi_lifespan_manager import State
9-
from models_library.rpc.notifications.messages import (
9+
from models_library.rpc.notifications.notifications import (
1010
EmailChannel,
11-
NotificationMessage,
11+
Notification,
1212
SMSChannel,
1313
)
1414
from settings_library.celery import CelerySettings
@@ -28,7 +28,7 @@ async def celery_lifespan(app: FastAPI) -> AsyncIterator[State]:
2828
)
2929

3030
register_celery_types()
31-
register_pydantic_types(NotificationMessage, EmailChannel, SMSChannel)
31+
register_pydantic_types(Notification, EmailChannel, SMSChannel)
3232
yield {}
3333

3434

services/notifications/src/simcore_service_notifications/modules/celery/_email_tasks.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,51 @@
33
import logging
44

55
from celery import Task
6-
from models_library.rpc.notifications.messages import EmailChannel, NotificationMessage
6+
from models_library.rpc.notifications.notifications import EmailChannel, Notification
77
from servicelib.celery.models import TaskID
88

99
_logger = logging.getLogger(__name__)
1010

1111
EMAIL_CHANNEL_NAME = "email"
1212

1313

14-
async def send_email(
14+
async def send_email_notification(
1515
task: Task,
1616
task_id: TaskID,
17-
message: NotificationMessage,
17+
notification: Notification,
1818
) -> None:
19-
assert isinstance(message.channel, EmailChannel) # nosec
19+
assert isinstance(notification.channel, EmailChannel) # nosec
2020

21-
_logger.info("Sending email notification to %s", message.channel.to)
21+
_logger.info("Sending email notification to %s", notification.channel.to)
22+
23+
# event_extra_data = event_extra_data | (asdict(sharer_data) if sharer_data else {})
24+
25+
# parts = render_email_parts(
26+
# env=create_render_environment_from_notifications_library(
27+
# undefined=StrictUndefined
28+
# ),
29+
# event_name=event_name,
30+
# user=user_data,
31+
# product=product_data,
32+
# # extras
33+
# **event_extra_data,
34+
# )
35+
36+
# from_ = get_support_address(product_data)
37+
# to = get_user_address(user_data)
38+
39+
# assert from_.addr_spec == product_data.support_email
40+
# assert to.addr_spec == user_email
41+
42+
# msg = compose_email(
43+
# from_,
44+
# to,
45+
# subject=parts.subject,
46+
# content_text=parts.text_content,
47+
# content_html=parts.html_content,
48+
# )
49+
# if event_attachments:
50+
# add_attachments(msg, event_attachments)
51+
52+
# async with create_email_session(settings=SMTPSettings.create_from_envs()) as smtp:
53+
# await smtp.send_message(msg)

services/notifications/src/simcore_service_notifications/modules/celery/tasks.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
from celery import Celery # type: ignore[import-untyped]
55
from celery_library.task import register_task
66
from celery_library.types import register_celery_types, register_pydantic_types
7-
from models_library.rpc.notifications.messages import (
7+
from models_library.rpc.notifications.account import AccountRequestedEvent
8+
from models_library.rpc.notifications.notifications import (
89
EmailChannel,
9-
NotificationMessage,
1010
SMSChannel,
1111
)
1212
from servicelib.logging_utils import log_context
1313

14-
from ...modules.celery._email_tasks import EMAIL_CHANNEL_NAME, send_email
14+
from ...modules.celery._email_tasks import EMAIL_CHANNEL_NAME, send_email_notification
1515

1616
_logger = logging.getLogger(__name__)
1717

@@ -25,9 +25,11 @@ class TaskQueue(StrEnum):
2525

2626
def setup_worker_tasks(app: Celery) -> None:
2727
register_celery_types()
28-
register_pydantic_types(NotificationMessage, EmailChannel, SMSChannel)
28+
register_pydantic_types(AccountRequestedEvent, EmailChannel, SMSChannel)
2929

3030
with log_context(_logger, logging.INFO, msg="worker tasks registration"):
3131
register_task(
32-
app, send_email, ".".join((_NOTIFICATIONS_PREFIX, EMAIL_CHANNEL_NAME))
32+
app,
33+
send_email_notification,
34+
".".join((_NOTIFICATIONS_PREFIX, EMAIL_CHANNEL_NAME)),
3335
)
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22

3-
from models_library.rpc.notifications.messages import NotificationMessage
3+
from models_library.rpc.notifications.notifications import Notification
44
from servicelib.celery.models import TaskContext
55
from servicelib.celery.task_manager import TaskManager
66

@@ -9,14 +9,15 @@
99
_logger = logging.getLogger(__name__)
1010

1111

12-
async def send_notification_message(
12+
async def send_notification(
1313
task_manager: TaskManager,
1414
*,
15-
message: NotificationMessage,
15+
notification: Notification,
1616
) -> None:
1717
await task_manager.send_task(
18-
name=f"notifications.{message.event_type}",
18+
# send to the specific channel worker
19+
name=f"notifications.{notification.channel.type}",
1920
context=TaskContext(), # TODO: TaskFilter
2021
queue=TaskQueue.DEFAULT,
21-
message=message,
22+
notification=notification,
2223
)
Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import pytest
2-
from models_library.rpc.notifications.messages import NotificationMessage
2+
from faker import Faker
3+
from models_library.rpc.notifications.notifications import (
4+
AccountRequestedEvent,
5+
Notification,
6+
)
37
from servicelib.rabbitmq import RabbitMQRPCClient
48
from servicelib.rabbitmq.rpc_interfaces.notifications.messages import (
5-
send_notification_message,
9+
send_notification,
610
)
711
from simcore_service_notifications.clients.celery import EmailChannel
812

@@ -17,14 +21,20 @@
1721
"mock_celery_worker",
1822
"fastapi_app",
1923
)
20-
async def test_send_email(
24+
async def test_account_requested(
2125
notifications_rabbitmq_rpc_client: RabbitMQRPCClient,
26+
faker: Faker,
2227
):
23-
await send_notification_message(
28+
email = faker.email()
29+
30+
await send_notification(
2431
notifications_rabbitmq_rpc_client,
25-
message=NotificationMessage(
26-
event_type="on_account_requested",
27-
channel=EmailChannel(to="[email protected]"),
28-
context={"key": "value"},
32+
notification=Notification(
33+
event=AccountRequestedEvent(
34+
first_name=faker.first_name(),
35+
last_name=faker.last_name(),
36+
email=email,
37+
),
38+
channel=EmailChannel(to=email),
2939
),
3040
)

0 commit comments

Comments
 (0)