sync
parent
0e2ecd3449
commit
2ca7787dcb
|
@ -1,5 +1,6 @@
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
from sqlalchemy.ext.asyncio import (AsyncEngine, AsyncSession,
|
||||||
|
async_sessionmaker)
|
||||||
|
|
||||||
from api.application.abstractions.uow import UnitOfWork
|
from api.application.abstractions.uow import UnitOfWork
|
||||||
from api.application.protocols.date_time import DateTimeProvider
|
from api.application.protocols.date_time import DateTimeProvider
|
||||||
|
@ -7,35 +8,28 @@ from api.application.protocols.jwt import JwtTokenProcessor
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
from api.application.usecase.auth.auth_user import LoginUser
|
from api.application.usecase.auth.auth_user import LoginUser
|
||||||
from api.application.usecase.auth.create_user import CreateUser
|
from api.application.usecase.auth.create_user import CreateUser
|
||||||
from api.application.usecase.company.get_users_company import GetCompaniesByOwnerEmail
|
from api.application.usecase.company.create_company import CreateCompany
|
||||||
|
from api.application.usecase.company.get_users_company import \
|
||||||
|
GetCompaniesByOwnerEmail
|
||||||
from api.domain.company.repository import CompanyRepository
|
from api.domain.company.repository import CompanyRepository
|
||||||
from api.domain.user.repository import UserRepository
|
from api.domain.user.repository import UserRepository
|
||||||
from api.infrastructure.auth.jwt_settings import JwtSettings
|
from api.infrastructure.auth.jwt_settings import JwtSettings
|
||||||
from api.infrastructure.dependencies.adapters import (
|
from api.infrastructure.dependencies.adapters import (create_engine,
|
||||||
create_engine,
|
|
||||||
create_session_maker,
|
create_session_maker,
|
||||||
new_session,
|
new_session,
|
||||||
new_unit_of_work,
|
new_unit_of_work)
|
||||||
)
|
from api.infrastructure.dependencies.configs import (app_settings,
|
||||||
from api.infrastructure.dependencies.configs import (
|
|
||||||
app_settings,
|
|
||||||
get_db_settings,
|
get_db_settings,
|
||||||
get_jwt_settings,
|
get_jwt_settings)
|
||||||
)
|
from api.infrastructure.dependencies.protocols import (get_date_time_provider,
|
||||||
from api.infrastructure.dependencies.protocols import (
|
|
||||||
get_date_time_provider,
|
|
||||||
get_jwt_token_processor,
|
get_jwt_token_processor,
|
||||||
get_password_hasher,
|
get_password_hasher,
|
||||||
get_user_login,
|
get_user_login)
|
||||||
)
|
|
||||||
from api.infrastructure.dependencies.repositories import (
|
from api.infrastructure.dependencies.repositories import (
|
||||||
get_company_repository,
|
get_company_repository, get_user_repository)
|
||||||
get_user_repository,
|
|
||||||
)
|
|
||||||
from api.infrastructure.dependencies.usecases import (
|
from api.infrastructure.dependencies.usecases import (
|
||||||
provide_create_user,
|
provide_create_company, provide_create_user,
|
||||||
provide_get_companies_by_email,
|
provide_get_companies_by_email)
|
||||||
)
|
|
||||||
from api.infrastructure.persistence.db_setings import DBSettings
|
from api.infrastructure.persistence.db_setings import DBSettings
|
||||||
from api.infrastructure.settings import Settings
|
from api.infrastructure.settings import Settings
|
||||||
|
|
||||||
|
@ -62,3 +56,4 @@ def init_dependencies(app: FastAPI) -> None:
|
||||||
|
|
||||||
app.dependency_overrides[CreateUser] = provide_create_user
|
app.dependency_overrides[CreateUser] = provide_create_user
|
||||||
app.dependency_overrides[GetCompaniesByOwnerEmail] = provide_get_companies_by_email
|
app.dependency_overrides[GetCompaniesByOwnerEmail] = provide_get_companies_by_email
|
||||||
|
app.dependency_overrides[CreateCompany] = provide_create_company
|
||||||
|
|
|
@ -8,11 +8,9 @@ from api.app_entrypoint.dependencies import init_dependencies
|
||||||
from api.app_entrypoint.error_handlers import init_exc_handlers
|
from api.app_entrypoint.error_handlers import init_exc_handlers
|
||||||
from api.infrastructure.auth.jwt_settings import JwtSettings
|
from api.infrastructure.auth.jwt_settings import JwtSettings
|
||||||
from api.infrastructure.dependencies.adapters import create_engine
|
from api.infrastructure.dependencies.adapters import create_engine
|
||||||
from api.infrastructure.dependencies.configs import (
|
from api.infrastructure.dependencies.configs import (app_settings,
|
||||||
app_settings,
|
|
||||||
get_db_settings,
|
get_db_settings,
|
||||||
get_jwt_settings,
|
get_jwt_settings)
|
||||||
)
|
|
||||||
from api.infrastructure.persistence.db_setings import DBSettings
|
from api.infrastructure.persistence.db_setings import DBSettings
|
||||||
from api.infrastructure.persistence.models import Base
|
from api.infrastructure.persistence.models import Base
|
||||||
from api.infrastructure.settings import Settings
|
from api.infrastructure.settings import Settings
|
||||||
|
|
|
@ -4,6 +4,7 @@ from dataclasses import dataclass
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class UserCreateRequest:
|
class UserCreateRequest:
|
||||||
name: str
|
name: str
|
||||||
|
last_name: str
|
||||||
email: str
|
email: str
|
||||||
password: str
|
password: str
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class CreateNewCompany:
|
||||||
|
name: str
|
||||||
|
email: str
|
||||||
|
address: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
from api.application.abstractions import UnitOfWork
|
from api.application.abstractions import UnitOfWork
|
||||||
from api.application.contracts.auth.auth_request import UserCreateRequest
|
from api.application.contracts.auth.auth_request import UserCreateRequest
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
|
from api.domain.user.error import UserAlreadyExistsError
|
||||||
from api.domain.user.model import User
|
from api.domain.user.model import User
|
||||||
from api.domain.user.repository import UserRepository
|
from api.domain.user.repository import UserRepository
|
||||||
|
|
||||||
|
@ -19,8 +22,18 @@ class CreateUser:
|
||||||
async def execute(self, request: UserCreateRequest) -> None:
|
async def execute(self, request: UserCreateRequest) -> None:
|
||||||
user = User.create(
|
user = User.create(
|
||||||
name=request.name,
|
name=request.name,
|
||||||
|
last_name=request.last_name,
|
||||||
email=request.email,
|
email=request.email,
|
||||||
hashed_password=self.hasher.hash_password(request.password),
|
hashed_password=self.hasher.hash_password(request.password),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
await self.user_repository.create_user(user=user)
|
await self.user_repository.create_user(user=user)
|
||||||
await self.uow.commit()
|
await self.uow.commit()
|
||||||
|
|
||||||
|
except IntegrityError as e:
|
||||||
|
msg = e.args[0].split("\n")[-1]
|
||||||
|
msg = msg.split(":")[1].strip()
|
||||||
|
|
||||||
|
if "email" in msg:
|
||||||
|
raise UserAlreadyExistsError(message=msg)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from api.application.contracts.company.company_request import CreateNewCompany
|
||||||
|
from api.application.contracts.company.company_response import CompanyBaseResponse
|
||||||
|
from api.domain.company.repository import CompanyRepository
|
||||||
|
|
||||||
|
|
||||||
|
class CreateCompany:
|
||||||
|
def __init__(self, company_repository: CompanyRepository) -> None:
|
||||||
|
self.company_repository = company_repository
|
||||||
|
|
||||||
|
async def execute(self, request: CreateNewCompany) -> CompanyBaseResponse:
|
||||||
|
# companies = await self.company_repository.
|
||||||
|
return CompanyBaseResponse(name=request.name, email=request.email)
|
|
@ -4,6 +4,7 @@ from uuid import UUID, uuid4
|
||||||
|
|
||||||
from api.domain import DomainValidationError
|
from api.domain import DomainValidationError
|
||||||
from api.domain.entity import DomainEntity
|
from api.domain.entity import DomainEntity
|
||||||
|
from api.domain.user.model import UserId
|
||||||
from api.domain.value_obj import DomainValueObject
|
from api.domain.value_obj import DomainValueObject
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +16,9 @@ class CompanyEmail(DomainValueObject):
|
||||||
pattern = r"^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$"
|
pattern = r"^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$"
|
||||||
|
|
||||||
if not re.match(pattern, self.value):
|
if not re.match(pattern, self.value):
|
||||||
raise DomainValidationError("Invalid email format. Email must be in the format 'example@example.com'.")
|
raise DomainValidationError(
|
||||||
|
"Invalid email format. Email must be in the format 'example@example.com'."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
@ -26,7 +29,9 @@ class CompanyName(DomainValueObject):
|
||||||
if len(self.value) < 1:
|
if len(self.value) < 1:
|
||||||
raise DomainValidationError("First name must be at least 1 character long.")
|
raise DomainValidationError("First name must be at least 1 character long.")
|
||||||
if len(self.value) > 100:
|
if len(self.value) > 100:
|
||||||
raise DomainValidationError("First name must be at most 100 characters long.")
|
raise DomainValidationError(
|
||||||
|
"First name must be at most 100 characters long."
|
||||||
|
)
|
||||||
if not self.value.isalpha():
|
if not self.value.isalpha():
|
||||||
raise DomainValidationError("First name must only contain letters.")
|
raise DomainValidationError("First name must only contain letters.")
|
||||||
|
|
||||||
|
@ -36,15 +41,32 @@ class CompanyId(DomainValueObject):
|
||||||
value: UUID
|
value: UUID
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class CompanyAddress(DomainValueObject):
|
||||||
|
value: str
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
if len(self.value) < 1:
|
||||||
|
raise DomainValidationError("Address must be at least 1 character long.")
|
||||||
|
if len(self.value) > 100:
|
||||||
|
raise DomainValidationError("Address must be at most 100 characters long.")
|
||||||
|
if not self.value.isalpha():
|
||||||
|
raise DomainValidationError("Address must only contain letters.")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Company(DomainEntity[CompanyId]):
|
class Company(DomainEntity[CompanyId]):
|
||||||
name: CompanyName
|
name: CompanyName
|
||||||
email: CompanyEmail
|
email: CompanyEmail
|
||||||
|
address: CompanyAddress
|
||||||
|
owner_id: UserId
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(name: str, email: str) -> "Company":
|
def create(name: str, email: str, address: str, owner_id: str) -> "Company":
|
||||||
return Company(
|
return Company(
|
||||||
id=CompanyId(uuid4()),
|
id=CompanyId(uuid4()),
|
||||||
name=CompanyName(name),
|
name=CompanyName(name),
|
||||||
email=CompanyEmail(email),
|
email=CompanyEmail(email),
|
||||||
|
address=CompanyAddress(address),
|
||||||
|
owner_id=UserId(UUID(owner_id)),
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,7 +15,9 @@ class UserEmail(DomainValueObject):
|
||||||
pattern = r"^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$"
|
pattern = r"^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$"
|
||||||
|
|
||||||
if not re.match(pattern, self.value):
|
if not re.match(pattern, self.value):
|
||||||
raise DomainValidationError("Invalid email format. Email must be in the format 'example@example.com'.")
|
raise DomainValidationError(
|
||||||
|
"Invalid email format. Email must be in the format 'example@example.com'."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
@ -26,7 +28,9 @@ class UserFirstName(DomainValueObject):
|
||||||
if len(self.value) < 1:
|
if len(self.value) < 1:
|
||||||
raise DomainValidationError("First name must be at least 1 character long.")
|
raise DomainValidationError("First name must be at least 1 character long.")
|
||||||
if len(self.value) > 100:
|
if len(self.value) > 100:
|
||||||
raise DomainValidationError("First name must be at most 100 characters long.")
|
raise DomainValidationError(
|
||||||
|
"First name must be at most 100 characters long."
|
||||||
|
)
|
||||||
if not self.value.isalpha():
|
if not self.value.isalpha():
|
||||||
raise DomainValidationError("First name must only contain letters.")
|
raise DomainValidationError("First name must only contain letters.")
|
||||||
|
|
||||||
|
@ -39,7 +43,9 @@ class UserLastName(DomainValueObject):
|
||||||
if len(self.value) < 1:
|
if len(self.value) < 1:
|
||||||
raise DomainValidationError("Last name must be at least 1 character long.")
|
raise DomainValidationError("Last name must be at least 1 character long.")
|
||||||
if len(self.value) > 100:
|
if len(self.value) > 100:
|
||||||
raise DomainValidationError("Last name must be at most 100 characters long.")
|
raise DomainValidationError(
|
||||||
|
"Last name must be at most 100 characters long."
|
||||||
|
)
|
||||||
if not self.value.isalpha():
|
if not self.value.isalpha():
|
||||||
raise DomainValidationError("Last name must only contain letters.")
|
raise DomainValidationError("Last name must only contain letters.")
|
||||||
|
|
||||||
|
@ -52,14 +58,16 @@ class UserId(DomainValueObject):
|
||||||
@dataclass
|
@dataclass
|
||||||
class User(DomainEntity[UserId]):
|
class User(DomainEntity[UserId]):
|
||||||
name: UserFirstName
|
name: UserFirstName
|
||||||
|
last_name: UserLastName
|
||||||
email: UserEmail
|
email: UserEmail
|
||||||
hashed_password: str
|
hashed_password: str
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(name: str, email: str, hashed_password: str) -> "User":
|
def create(name: str, last_name: str, email: str, hashed_password: str) -> "User":
|
||||||
return User(
|
return User(
|
||||||
id=UserId(uuid4()),
|
id=UserId(uuid4()),
|
||||||
name=UserFirstName(name),
|
name=UserFirstName(name),
|
||||||
|
last_name=UserLastName(last_name),
|
||||||
email=UserEmail(email),
|
email=UserEmail(email),
|
||||||
hashed_password=hashed_password,
|
hashed_password=hashed_password,
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,7 +5,9 @@ from fastapi import Depends
|
||||||
from api.application.abstractions.uow import UnitOfWork
|
from api.application.abstractions.uow import UnitOfWork
|
||||||
from api.application.protocols.password_hasher import PasswordHasher
|
from api.application.protocols.password_hasher import PasswordHasher
|
||||||
from api.application.usecase.auth.create_user import CreateUser
|
from api.application.usecase.auth.create_user import CreateUser
|
||||||
from api.application.usecase.company.get_users_company import GetCompaniesByOwnerEmail
|
from api.application.usecase.company.create_company import CreateCompany
|
||||||
|
from api.application.usecase.company.get_users_company import \
|
||||||
|
GetCompaniesByOwnerEmail
|
||||||
from api.domain.company.repository import CompanyRepository
|
from api.domain.company.repository import CompanyRepository
|
||||||
from api.domain.user.repository import UserRepository
|
from api.domain.user.repository import UserRepository
|
||||||
from api.infrastructure.dependencies.stub import Stub
|
from api.infrastructure.dependencies.stub import Stub
|
||||||
|
@ -16,10 +18,18 @@ def provide_create_user(
|
||||||
uow: Annotated[UnitOfWork, Depends(Stub(UnitOfWork))],
|
uow: Annotated[UnitOfWork, Depends(Stub(UnitOfWork))],
|
||||||
password_hasher: Annotated[PasswordHasher, Depends(Stub(PasswordHasher))],
|
password_hasher: Annotated[PasswordHasher, Depends(Stub(PasswordHasher))],
|
||||||
) -> CreateUser:
|
) -> CreateUser:
|
||||||
return CreateUser(uow=uow, user_repository=user_repository, password_hasher=password_hasher)
|
return CreateUser(
|
||||||
|
uow=uow, user_repository=user_repository, password_hasher=password_hasher
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def provide_get_companies_by_email(
|
def provide_get_companies_by_email(
|
||||||
company_repository: Annotated[CompanyRepository, Depends(Stub(CompanyRepository))],
|
company_repository: Annotated[CompanyRepository, Depends(Stub(CompanyRepository))],
|
||||||
) -> GetCompaniesByOwnerEmail:
|
) -> GetCompaniesByOwnerEmail:
|
||||||
return GetCompaniesByOwnerEmail(company_repository=company_repository)
|
return GetCompaniesByOwnerEmail(company_repository=company_repository)
|
||||||
|
|
||||||
|
|
||||||
|
def provide_create_company(
|
||||||
|
company_repository: Annotated[CompanyRepository, Depends(Stub(CompanyRepository))]
|
||||||
|
) -> CreateCompany:
|
||||||
|
return CreateCompany(company_repository=company_repository)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
class TransactionContextManagerError(Exception):
|
||||||
|
def __init__(self, message: str, *args: object) -> None:
|
||||||
|
self.message = message
|
||||||
|
super().__init__(*args)
|
|
@ -1,13 +1,13 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy import UUID
|
from sqlalchemy import UUID, ForeignKey
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from api.infrastructure.persistence.models.base import Base
|
from api.infrastructure.persistence.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
class CompanyModel(Base):
|
class CompanyModel(Base):
|
||||||
__tablename__ = "companies"
|
__tablename__ = "company"
|
||||||
|
|
||||||
id: Mapped[uuid.UUID] = mapped_column(
|
id: Mapped[uuid.UUID] = mapped_column(
|
||||||
UUID(as_uuid=True),
|
UUID(as_uuid=True),
|
||||||
|
@ -15,3 +15,45 @@ class CompanyModel(Base):
|
||||||
)
|
)
|
||||||
name: Mapped[str]
|
name: Mapped[str]
|
||||||
email: Mapped[str] = mapped_column(unique=True)
|
email: Mapped[str] = mapped_column(unique=True)
|
||||||
|
address: Mapped[str]
|
||||||
|
owner_id: Mapped[uuid.UUID] = mapped_column(
|
||||||
|
ForeignKey("users.id", ondelete="CASCADE"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DepartmentModel(Base):
|
||||||
|
__tablename__ = "department"
|
||||||
|
|
||||||
|
id: Mapped[uuid.UUID] = mapped_column(
|
||||||
|
UUID(as_uuid=True),
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
name: Mapped[str]
|
||||||
|
address: Mapped[str]
|
||||||
|
company_id: Mapped[uuid.UUID] = mapped_column(
|
||||||
|
ForeignKey("company.id", ondelete="CASCADE")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyDepartmentModel(Base):
|
||||||
|
__tablename__ = "company_department_m2m"
|
||||||
|
company_id: Mapped[uuid.UUID] = mapped_column(
|
||||||
|
ForeignKey("company.id", ondelete="CASCADE"),
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
department_id: Mapped[uuid.UUID] = mapped_column(
|
||||||
|
ForeignKey("department.id", ondelete="CASCADE"),
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DepartmentUserModel(Base):
|
||||||
|
__tablename__ = "department_user_m2m"
|
||||||
|
department_id: Mapped[uuid.UUID] = mapped_column(
|
||||||
|
ForeignKey("department.id", ondelete="CASCADE"),
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
user_id: Mapped[uuid.UUID] = mapped_column(
|
||||||
|
ForeignKey("users.id"),
|
||||||
|
primary_key=True,
|
||||||
|
)
|
||||||
|
|
|
@ -14,5 +14,6 @@ class UserModel(Base):
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
)
|
)
|
||||||
name: Mapped[str]
|
name: Mapped[str]
|
||||||
|
last_name: Mapped[str]
|
||||||
email: Mapped[str] = mapped_column(unique=True)
|
email: Mapped[str] = mapped_column(unique=True)
|
||||||
hashed_password: Mapped[str]
|
hashed_password: Mapped[str]
|
||||||
|
|
|
@ -1,30 +1,33 @@
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from api.domain.company.model import Company, CompanyEmail, CompanyId, CompanyName
|
from api.domain.company.model import (Company, CompanyAddress, CompanyEmail,
|
||||||
|
CompanyId, CompanyName)
|
||||||
from api.domain.company.repository import CompanyRepository
|
from api.domain.company.repository import CompanyRepository
|
||||||
|
from api.domain.user.model import UserId
|
||||||
|
|
||||||
|
|
||||||
class SqlAlchemyCompanyRepository(CompanyRepository):
|
class SqlAlchemyCompanyRepository(CompanyRepository):
|
||||||
def __init__(self, session: AsyncSession) -> None:
|
def __init__(self, session: AsyncSession) -> None:
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|
||||||
# async def create_user(self, user: User) -> None:
|
async def create_company(self, company: Company) -> None:
|
||||||
# stmt = text(
|
stmt = text(
|
||||||
# """INSERT INTO users (id, name, email, hashed_password)
|
"""INSERT INTO company (id, name, email, address, owner_id)
|
||||||
# VALUES(:id, :name, :email, :hashed_password)
|
VALUES(:id, :name, :email, :address, :owner_id)
|
||||||
# """
|
"""
|
||||||
# )
|
)
|
||||||
# await self.session.execute(
|
await self.session.execute(
|
||||||
# stmt,
|
stmt,
|
||||||
# {
|
{
|
||||||
# "id": str(user.id.value),
|
"id": str(company.id.value),
|
||||||
# "name": user.name.value,
|
"name": company.name.value,
|
||||||
# "email": user.email.value,
|
"email": company.email.value,
|
||||||
# "hashed_password": user.hashed_password,
|
"address": company.address.value,
|
||||||
# },
|
"owner_id": str(company.owner_id.value),
|
||||||
# )
|
},
|
||||||
#
|
)
|
||||||
|
|
||||||
async def get_companies_by_owner_email(self, filter: dict) -> list[Company]:
|
async def get_companies_by_owner_email(self, filter: dict) -> list[Company]:
|
||||||
stmt = text("""SELECT * FROM companies WHERE email = :val""")
|
stmt = text("""SELECT * FROM companies WHERE email = :val""")
|
||||||
result = await self.session.execute(stmt, {"val": filter["email"]})
|
result = await self.session.execute(stmt, {"val": filter["email"]})
|
||||||
|
@ -36,6 +39,8 @@ class SqlAlchemyCompanyRepository(CompanyRepository):
|
||||||
id=CompanyId(c.id),
|
id=CompanyId(c.id),
|
||||||
name=CompanyName(c.name),
|
name=CompanyName(c.name),
|
||||||
email=CompanyEmail(c.email),
|
email=CompanyEmail(c.email),
|
||||||
|
address=CompanyAddress(c.address),
|
||||||
|
owner_id=UserId(c.owner_id),
|
||||||
)
|
)
|
||||||
for c in result
|
for c in result
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,7 +2,8 @@ from sqlalchemy import text
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from api.domain.user import User, UserRepository
|
from api.domain.user import User, UserRepository
|
||||||
from api.domain.user.model import UserEmail, UserFirstName, UserId
|
from api.domain.user.model import (UserEmail, UserFirstName, UserId,
|
||||||
|
UserLastName)
|
||||||
|
|
||||||
|
|
||||||
class SqlAlchemyUserRepository(UserRepository):
|
class SqlAlchemyUserRepository(UserRepository):
|
||||||
|
@ -11,8 +12,8 @@ class SqlAlchemyUserRepository(UserRepository):
|
||||||
|
|
||||||
async def create_user(self, user: User) -> None:
|
async def create_user(self, user: User) -> None:
|
||||||
stmt = text(
|
stmt = text(
|
||||||
"""INSERT INTO users (id, name, email, hashed_password)
|
"""INSERT INTO users (id, name, last_name, email, hashed_password)
|
||||||
VALUES(:id, :name, :email, :hashed_password)
|
VALUES(:id, :name, :last_name, :email, :hashed_password)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
await self.session.execute(
|
await self.session.execute(
|
||||||
|
@ -20,6 +21,7 @@ class SqlAlchemyUserRepository(UserRepository):
|
||||||
{
|
{
|
||||||
"id": str(user.id.value),
|
"id": str(user.id.value),
|
||||||
"name": user.name.value,
|
"name": user.name.value,
|
||||||
|
"last_name": user.last_name.value,
|
||||||
"email": user.email.value,
|
"email": user.email.value,
|
||||||
"hashed_password": user.hashed_password,
|
"hashed_password": user.hashed_password,
|
||||||
},
|
},
|
||||||
|
@ -37,6 +39,7 @@ class SqlAlchemyUserRepository(UserRepository):
|
||||||
return User(
|
return User(
|
||||||
id=UserId(result.id),
|
id=UserId(result.id),
|
||||||
name=UserFirstName(result.name),
|
name=UserFirstName(result.name),
|
||||||
|
last_name=UserLastName(result.last_name),
|
||||||
email=UserEmail(result.email),
|
email=UserEmail(result.email),
|
||||||
hashed_password=result.hashed_password,
|
hashed_password=result.hashed_password,
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
from types import TracebackType
|
||||||
|
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from api.infrastructure.persistence.error import TransactionContextManagerError
|
||||||
|
|
||||||
|
|
||||||
|
class SqlalchemyTransactionContextManager:
|
||||||
|
def __init__(self, session: AsyncSession):
|
||||||
|
self._session = session
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(
|
||||||
|
self,
|
||||||
|
exc_type: type[BaseException],
|
||||||
|
exc_val: BaseException,
|
||||||
|
exc_tb: TracebackType,
|
||||||
|
) -> None:
|
||||||
|
if exc_type:
|
||||||
|
await self.rollback()
|
||||||
|
raise TransactionContextManagerError(message="Transaction Error")
|
||||||
|
|
||||||
|
async def commit(self):
|
||||||
|
await self._session.commit()
|
||||||
|
|
||||||
|
async def rollback(self):
|
||||||
|
await self._session.rollback()
|
|
@ -2,31 +2,42 @@ from typing import Annotated
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
|
|
||||||
from api.application.contracts.company.company_request import CompanyByOwnerEmail
|
from api.application.contracts.company.company_request import (
|
||||||
|
CompanyByOwnerEmail,
|
||||||
|
CreateNewCompany,
|
||||||
|
)
|
||||||
from api.application.contracts.company.company_response import CompanyBaseResponse
|
from api.application.contracts.company.company_response import CompanyBaseResponse
|
||||||
from api.application.protocols.jwt import JwtTokenProcessor
|
from api.application.protocols.jwt import JwtTokenProcessor
|
||||||
|
from api.application.usecase.company.create_company import CreateCompany
|
||||||
from api.application.usecase.company.get_users_company import GetCompaniesByOwnerEmail
|
from api.application.usecase.company.get_users_company import GetCompaniesByOwnerEmail
|
||||||
from api.domain.user.error import UserValidationError
|
from api.domain.user.error import UserValidationError
|
||||||
from api.infrastructure.dependencies.stub import Stub
|
from api.infrastructure.dependencies.stub import Stub
|
||||||
from api.presentation.auth.fasapi_auth import auth_required
|
from api.presentation.auth.fasapi_auth import auth_required
|
||||||
|
|
||||||
company_router = APIRouter(prefix="/company", tags=["Company"])
|
company_router = APIRouter(
|
||||||
|
prefix="/me",
|
||||||
|
tags=["Company"],
|
||||||
|
dependencies=[Depends(auth_required)],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@company_router.get(
|
@company_router.get(
|
||||||
"/",
|
"/companies",
|
||||||
response_model=None,
|
response_model=list[CompanyBaseResponse],
|
||||||
dependencies=[Depends(auth_required)],
|
|
||||||
)
|
)
|
||||||
async def get_companies(
|
async def get_my_companies(
|
||||||
request: Request,
|
request: Request,
|
||||||
token_processor: Annotated[JwtTokenProcessor, Depends(Stub(JwtTokenProcessor))],
|
token_processor: Annotated[JwtTokenProcessor, Depends(Stub(JwtTokenProcessor))],
|
||||||
usecase: Annotated[GetCompaniesByOwnerEmail, Depends(Stub(GetCompaniesByOwnerEmail))],
|
usecase: Annotated[
|
||||||
|
GetCompaniesByOwnerEmail, Depends(Stub(GetCompaniesByOwnerEmail))
|
||||||
|
],
|
||||||
) -> list[CompanyBaseResponse]:
|
) -> list[CompanyBaseResponse]:
|
||||||
token_data = token_processor.validate_token(request.scope["auth"])
|
token_data = token_processor.validate_token(request.scope["auth"])
|
||||||
if not token_data:
|
if not token_data:
|
||||||
raise UserValidationError("Login required")
|
raise UserValidationError("Login required")
|
||||||
companies = await usecase.execute(request=CompanyByOwnerEmail(email=token_data[1].value))
|
companies = await usecase.execute(
|
||||||
|
request=CompanyByOwnerEmail(email=token_data[1].value)
|
||||||
|
)
|
||||||
return [
|
return [
|
||||||
CompanyBaseResponse(
|
CompanyBaseResponse(
|
||||||
name=c.name,
|
name=c.name,
|
||||||
|
@ -34,3 +45,18 @@ async def get_companies(
|
||||||
)
|
)
|
||||||
for c in companies
|
for c in companies
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@company_router.post("/companies/create", response_model=CompanyBaseResponse)
|
||||||
|
async def create_new_company(
|
||||||
|
request: Request,
|
||||||
|
request_data: CreateNewCompany,
|
||||||
|
token_processor: Annotated[JwtTokenProcessor, Depends(Stub(JwtTokenProcessor))],
|
||||||
|
usecase: Annotated[CreateCompany, Depends(Stub(CreateCompany))],
|
||||||
|
) -> CompanyBaseResponse:
|
||||||
|
token_data = token_processor.validate_token(request.scope["auth"])
|
||||||
|
if not token_data:
|
||||||
|
raise UserValidationError("Login required")
|
||||||
|
|
||||||
|
company = await usecase.execute(request=request_data)
|
||||||
|
return company
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
db:
|
db:
|
||||||
host: "db"
|
host: "localhost"
|
||||||
port: 5432
|
port: 5432
|
||||||
database: "serviceman_db"
|
database: "serviceman_db"
|
||||||
user: "demo_user"
|
user: "demo_user"
|
||||||
|
|
Loading…
Reference in New Issue