add user password hasher and depebdency

This commit is contained in:
2024-04-01 01:12:01 +03:00
parent 7eaa082b41
commit 4e6aee8c3a
22 changed files with 310 additions and 366 deletions

View File

@@ -1,3 +1,6 @@
from .error import DomainError
from .error import DomainError, DomainValidationError
__all__ = ("DomainError",)
__all__ = (
"DomainError",
"DomainValidationError",
)

11
api/domain/entity.py Normal file
View File

@@ -0,0 +1,11 @@
from dataclasses import dataclass
from typing import Generic, TypeVar
from api.domain.value_obj import DomainValueObject
EntityId = TypeVar("EntityId", bound=DomainValueObject)
@dataclass
class DomainEntity(Generic[EntityId]):
id: EntityId

View File

@@ -1,4 +1,8 @@
class DomainError(Exception):
def __init__(self, message: str, *args: object) -> None:
super().__init__(*args)
self.message = message
super().__init__(*args)
class DomainValidationError(DomainError):
pass

View File

@@ -7,3 +7,15 @@ class UserNotFoundError(DomainError):
class UserValidationError(DomainError):
...
class UserInvalidCredentialsError(DomainError):
...
class UserAlreadyExistsError(DomainError):
...
class UserIsNotAuthorizedError(DomainError):
...

View File

@@ -1,33 +1,65 @@
import re
from dataclasses import dataclass
from uuid import UUID, uuid4
from api.domain.user import UserValidationError
from api.domain import DomainValidationError
from api.domain.entity import DomainEntity
from api.domain.value_obj import DomainValueObject
@dataclass(frozen=True)
class UserEmail(DomainValueObject):
value: str
def __post_init__(self) -> None:
pattern = r"^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$"
if not re.match(pattern, self.value):
raise DomainValidationError("Invalid email format. Email must be in the format 'example@example.com'.")
@dataclass(frozen=True)
class UserFirstName(DomainValueObject):
value: str
def __post_init__(self) -> None:
if len(self.value) < 1:
raise DomainValidationError("First name must be at least 1 character long.")
if len(self.value) > 100:
raise DomainValidationError("First name must be at most 100 characters long.")
if not self.value.isalpha():
raise DomainValidationError("First name must only contain letters.")
@dataclass(frozen=True)
class UserLastName(DomainValueObject):
value: str
def __post_init__(self) -> None:
if len(self.value) < 1:
raise DomainValidationError("Last name must be at least 1 character long.")
if len(self.value) > 100:
raise DomainValidationError("Last name must be at most 100 characters long.")
if not self.value.isalpha():
raise DomainValidationError("Last name must only contain letters.")
@dataclass(frozen=True)
class UserId(DomainValueObject):
value: UUID
@dataclass
class User:
id: UUID
name: str
email: str
password: str
class User(DomainEntity[UserId]):
name: UserFirstName
email: UserEmail
hashed_password: str
@staticmethod
def create(name: str, email: str, password: str) -> "User":
if not name:
raise UserValidationError("User name cannot be empty")
if not email:
raise UserValidationError("User email cannot be empty")
if len(name) > 50:
raise UserValidationError("User name cannot be longer than 50 characters")
if len(email) > 30:
raise UserValidationError("User email cannot be longer than 30 characters")
def create(name: str, email: str, hashed_password: str) -> "User":
return User(
id=uuid4(),
name=name,
email=email,
password=password,
id=UserId(uuid4()),
name=UserFirstName(name),
email=UserEmail(email),
hashed_password=hashed_password,
)

6
api/domain/value_obj.py Normal file
View File

@@ -0,0 +1,6 @@
from dataclasses import dataclass
@dataclass(frozen=True)
class DomainValueObject:
pass