Skip to content

Commit

Permalink
Pass user_id to register user service
Browse files Browse the repository at this point in the history
  • Loading branch information
lucassus committed Aug 25, 2023
1 parent c5c61d1 commit b2d89b7
Show file tree
Hide file tree
Showing 12 changed files with 45 additions and 23 deletions.
4 changes: 1 addition & 3 deletions app/infrastructure/tables.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import uuid

from sqlalchemy.sql.schema import Column, ForeignKey, MetaData, Table, UniqueConstraint
from sqlalchemy.sql.sqltypes import DateTime, Integer, String, Uuid

Expand All @@ -10,7 +8,7 @@
users_table = Table(
"users",
metadata,
Column("id", Uuid(), primary_key=True, default=lambda: uuid.uuid4()),
Column("id", Uuid(), primary_key=True),
Column("email", EmailType(), nullable=False, unique=True),
Column("password", PasswordType(), nullable=False),
)
Expand Down
6 changes: 2 additions & 4 deletions app/modules/accounts/application/register_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ def __init__(self, *, uow: AbstractUnitOfWork, bus: MessageBus):
self._uow = uow
self._bus = bus

def __call__(self, *, email: EmailAddress, password: Password) -> UserID:
def __call__(self, user_id: UserID, *, email: EmailAddress, password: Password):
with self._uow as uow:
if uow.user.exists_by_email(email):
raise EmailAlreadyExistsException(email)

user = uow.user.create(User(email=email, password=password))
user = uow.user.create(User(id=user_id, email=email, password=password))
uow.commit()

self._bus.dispatch(User.AccountCreatedEvent(user_id=user.id))

return user.id
21 changes: 16 additions & 5 deletions app/modules/accounts/application/register_user_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@ def register_user(uow: FakeUnitOfWork, message_bus):
return RegisterUser(uow=uow, bus=message_bus)


def test_register_user_returns_user_id(
def test_register_user_creates_a_user(
uow,
register_user: RegisterUser,
):
# When
user_id = register_user(email=EmailAddress("test@email.com"), password=Password("passwd123"))
register_user(
user_id=UserID.generate(),
email=EmailAddress("test@email.com"),
password=Password("passwd123"),
)

# Then
assert isinstance(user_id, UserID)
assert uow.committed is True
assert uow.user.exists_by_email(EmailAddress("test@email.com")) is True


def test_register_user_dispatches_account_created_event(
Expand All @@ -41,7 +45,12 @@ def test_register_user_dispatches_account_created_event(
message_bus.listen(User.AccountCreatedEvent, listener_mock)

# When
user_id = register_user(email=EmailAddress("test@email.com"), password=Password("passwd123"))
user_id = UserID.generate()
register_user(
user_id=user_id,
email=EmailAddress("test@email.com"),
password=Password("passwd123"),
)

# Then
listener_mock.assert_called_once_with(User.AccountCreatedEvent(user_id=user_id))
Expand All @@ -53,14 +62,16 @@ def test_register_user_validate_email_uniqueness(
repository: AbstractUserRepository,
register_user: RegisterUser,
):
repository.create(UserBuilder().with_email("existing@email.com").build())
existing_user = UserBuilder().with_email("existing@email.com").build()
repository.create(existing_user)

# Then
with pytest.raises(
EmailAlreadyExistsException,
match="A user with the email existing@email.com already exists",
):
register_user(
user_id=UserID.generate(),
email=EmailAddress("existing@email.com"),
password=Password("passwd123"),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ def __init__(self):
self._users_by_id = {}

def create(self, user: User) -> User:
user._id = self._get_next_id()
self._users_by_id[user.id] = user

return user
Expand All @@ -28,6 +27,3 @@ def get_by_email(self, email: EmailAddress) -> User | None:
return user

return None

def _get_next_id(self) -> UserID:
return UserID.generate()
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@

def test_fake_repository():
repository = FakeUserRepository()

user = repository.create(UserBuilder().build())
assert user.id is not None

loaded = repository.get(user.id)
assert loaded is not None
Expand Down
2 changes: 2 additions & 0 deletions app/modules/accounts/domain/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ class AccountCreatedEvent(BaseEvent):

def __init__(
self,
id: UserID,
email: EmailAddress,
password: Password,
):
self._id = id
self._email = email
self._password = password

Expand Down
14 changes: 13 additions & 1 deletion app/modules/accounts/domain/user_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@
from app.modules.accounts.domain.password import Password
from app.modules.accounts.domain.user import User
from app.modules.shared_kernel.entities.email_address import EmailAddress
from app.modules.shared_kernel.entities.user_id import UserID


class UserBuilder:
# Provide some sane defaults
_email = EmailAddress("test@email.com")
_password = Password("password")

def __init__(self):
self._id = UserID.generate()

def with_id(self, id: UserID) -> Self:
self._id = id
return self

def with_email(self, email: str | EmailAddress) -> Self:
self._email = EmailAddress(str(email))
return self
Expand All @@ -19,4 +27,8 @@ def with_password(self, password: str | Password) -> Self:
return self

def build(self) -> User:
return User(email=self._email, password=self._password)
return User(
id=self._id,
email=self._email,
password=self._password,
)
5 changes: 4 additions & 1 deletion app/modules/accounts/entrypoints/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from app.modules.accounts.entrypoints.dependencies import get_current_user
from app.modules.accounts.queries.find_user_query import GetUserQuery
from app.modules.authentication_contract import AuthenticationContract
from app.modules.shared_kernel.entities.user_id import UserID

router = APIRouter(prefix="/users", tags=["users"])

Expand All @@ -26,8 +27,10 @@ def user_register_endpoint(
register_user: RegisterUser = Depends(Provide[Container.application.register_user]),
auth_token: AuthenticationToken = Depends(Provide[Container.application.auth_token]),
):
user_id = UserID.generate()

try:
user_id = register_user(email=data.email, password=data.password)
register_user(user_id, email=data.email, password=data.password)
except EmailAlreadyExistsException as e:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
Expand Down
4 changes: 3 additions & 1 deletion app/modules/accounts/entrypoints/routes_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from starlette import status
from starlette.testclient import TestClient

from app.anys import AnyUUID
from app.modules.accounts.domain.errors import EmailAlreadyExistsException
from app.modules.accounts.domain.password import Password
from app.modules.accounts.entrypoints.containers import Container
Expand All @@ -17,7 +18,7 @@

def test_register_user_endpoint(container: Container, client: TestClient):
# Given
register_user_mock = Mock(return_value=123)
register_user_mock = Mock()

# When
with container.application.register_user.override(register_user_mock):
Expand All @@ -32,6 +33,7 @@ def test_register_user_endpoint(container: Container, client: TestClient):

# Then
register_user_mock.assert_called_with(
AnyUUID,
email=EmailAddress("test@email.com"),
password=Password("password"),
)
Expand Down
2 changes: 2 additions & 0 deletions app/seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from app.modules.projects.infrastructure.adapters.unit_of_work import UnitOfWork as ProjectsUnitOfWork
from app.modules.projects.infrastructure.mappers import start_mappers as start_project_mappers
from app.modules.shared_kernel.entities.email_address import EmailAddress
from app.modules.shared_kernel.entities.user_id import UserID
from app.modules.shared_kernel.message_bus import BaseEvent, MessageBus


Expand Down Expand Up @@ -49,6 +50,7 @@ def main(rebuild_db: bool = True):
start_project_mappers(mapper_registry)

user_id = register_user(
user_id=UserID.generate(),
email=EmailAddress("test@email.com"),
password=Password("password"),
)
Expand Down
2 changes: 0 additions & 2 deletions tests/end-to-end/test_project_tasks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from unittest.mock import ANY

from starlette import status
from starlette.testclient import TestClient

Expand Down
2 changes: 2 additions & 0 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from app.modules.projects.domain.project import Project, ProjectName
from app.modules.projects.infrastructure.adapters.project_repository import ProjectRepository
from app.modules.shared_kernel.entities.email_address import EmailAddress
from app.modules.shared_kernel.entities.user_id import UserID


@pytest.fixture()
Expand All @@ -15,6 +16,7 @@ def create_user(session: Session):

def _create_user(email: EmailAddress | None = None):
user = User(
id=UserID.generate(),
email=email or EmailAddress("test@email.com"),
password=Password("password"),
)
Expand Down

0 comments on commit b2d89b7

Please sign in to comment.