Skip to content

Commit

Permalink
feat: add users interface, restructure the ports
Browse files Browse the repository at this point in the history
  • Loading branch information
ShahriyarR committed Oct 23, 2022
1 parent 220af22 commit d4b7c03
Show file tree
Hide file tree
Showing 16 changed files with 72 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/jobboard/adapters/entrypoints/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from src.jobboard.domain.ports.responses import ResponseTypes
from src.jobboard.domain.ports.common.responses import ResponseTypes

STATUS_CODES = {
ResponseTypes.SUCCESS: 200,
Expand Down
4 changes: 2 additions & 2 deletions src/jobboard/adapters/entrypoints/api/v1/route_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
from src.jobboard.adapters.entrypoints.api.v1.route_login import (
get_current_user_from_token,
)
from src.jobboard.configurator.containers import Container
from src.jobboard.domain.model.model import User
from src.jobboard.domain.ports.common.responses import ResponseTypes
from src.jobboard.domain.ports.use_cases.jobs import JobsServiceInterface
from src.jobboard.domain.ports.responses import ResponseTypes
from src.jobboard.domain.schemas.jobs import JobCreateInputDto
from src.jobboard.configurator.containers import Container

router = APIRouter()
templates = Jinja2Templates(directory="src/jobboard/adapters/entrypoints/templates")
Expand Down
10 changes: 5 additions & 5 deletions src/jobboard/adapters/entrypoints/api/v1/route_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
from jose import JWTError, jwt

from src.jobboard.adapters.entrypoints.api.utils import OAuth2PasswordBearerWithCookie
from src.jobboard.domain.ports.user_service import UserService
from src.jobboard.domain.schemas.tokens import Token
from src.jobboard.domain.schemas.users import UserLoginInputDto, UserOutputDto
from src.jobboard.configurator.config import settings
from src.jobboard.configurator.containers import Container
from src.jobboard.configurator.security import create_access_token
from src.jobboard.domain.ports.use_cases.users import UsersServiceInterface
from src.jobboard.domain.schemas.tokens import Token
from src.jobboard.domain.schemas.users import UserLoginInputDto, UserOutputDto

router = APIRouter()

Expand All @@ -21,7 +21,7 @@
def login_for_access_token(
response: Response,
form_data: OAuth2PasswordRequestForm = Depends(),
user_service: UserService = Depends(Provide[Container.user_service]),
user_service: UsersServiceInterface = Depends(Provide[Container.user_service]),
):
user = UserLoginInputDto(email=form_data.username, password=form_data.password)
user = user_service.authenticate_user(user)
Expand All @@ -46,7 +46,7 @@ def login_for_access_token(
@inject
def get_current_user_from_token(
token: str = Depends(oauth2_scheme),
user_service: UserService = Depends(Provide[Container.user_service]),
user_service: UsersServiceInterface = Depends(Provide[Container.user_service]),
):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
Expand Down
6 changes: 3 additions & 3 deletions src/jobboard/adapters/entrypoints/api/v1/route_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from fastapi.encoders import jsonable_encoder

from src.jobboard.adapters.entrypoints import STATUS_CODES
from src.jobboard.domain.ports.user_service import UserService
from src.jobboard.domain.schemas.users import UserCreateInputDto
from src.jobboard.configurator.containers import Container
from src.jobboard.domain.ports.use_cases.users import UsersServiceInterface
from src.jobboard.domain.schemas.users import UserCreateInputDto

router = APIRouter()

Expand All @@ -16,7 +16,7 @@
@inject
def create_user(
user: UserCreateInputDto,
user_service: UserService = Depends(Provide[Container.user_service]),
user_service: UsersServiceInterface = Depends(Provide[Container.user_service]),
):
response = user_service.create(user=user)
data = jsonable_encoder(response.value)
Expand Down
5 changes: 3 additions & 2 deletions src/jobboard/adapters/entrypoints/webapps/jobs/route_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
get_current_user_from_token,
)
from src.jobboard.adapters.entrypoints.webapps.jobs.forms import JobCreateForm
from src.jobboard.configurator.containers import Container
from src.jobboard.domain.model.model import User
from src.jobboard.domain.ports.use_cases.jobs import JobsServiceInterface
from src.jobboard.domain.schemas.jobs import JobCreateInputDto
from src.jobboard.configurator.containers import Container

templates = Jinja2Templates(directory="src/jobboard/adapters/entrypoints/templates")
router = APIRouter(include_in_schema=False)
Expand Down Expand Up @@ -81,7 +81,8 @@ async def create_job(
@router.get("/delete-job/")
@inject
def show_jobs_to_delete(
request: Request, job_service: JobsServiceInterface = Depends(Provide[Container.job_service])
request: Request,
job_service: JobsServiceInterface = Depends(Provide[Container.job_service]),
):
jobs = job_service.list_jobs()
return templates.TemplateResponse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from sqlalchemy.exc import IntegrityError

from src.jobboard.adapters.entrypoints.webapps.users.forms import UserCreateForm
from src.jobboard.domain.ports.user_service import UserService
from src.jobboard.domain.schemas.users import UserCreateInputDto
from src.jobboard.configurator.containers import Container
from src.jobboard.domain.ports.use_cases.users import UsersServiceInterface
from src.jobboard.domain.schemas.users import UserCreateInputDto

templates = Jinja2Templates(directory="src/jobboard/adapters/entrypoints/templates")
router = APIRouter(include_in_schema=False)
Expand All @@ -21,7 +21,7 @@ def register(request: Request):
@inject
async def register(
request: Request,
user_service: UserService = Depends(Provide[Container.user_service]),
user_service: UsersServiceInterface = Depends(Provide[Container.user_service]),
):
form = UserCreateForm(request)
await form.load_data()
Expand Down
2 changes: 1 addition & 1 deletion src/jobboard/adapters/use_cases/jobs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Union

from src.jobboard.domain.model.model import job_model_event_factory
from src.jobboard.domain.ports.responses import (
from src.jobboard.domain.ports.common.responses import (
ResponseFailure,
ResponseSuccess,
ResponseTypes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
from typing import Union

from src.jobboard.configurator.hashing import Hasher
from src.jobboard.domain.model.model import user_model_event_factory
from src.jobboard.domain.ports.responses import (
from src.jobboard.domain.ports.common.responses import (
ResponseFailure,
ResponseSuccess,
ResponseTypes,
)
from src.jobboard.domain.ports.unit_of_work import UserUnitOfWorkInterface
from src.jobboard.domain.ports.use_cases.users import UsersServiceInterface
from src.jobboard.domain.schemas.users import (
UserCreateInputDto,
UserLoginInputDto,
UserOutputDto,
)
from src.jobboard.configurator.hashing import Hasher


class UserService:
class UsersService(UsersServiceInterface):
def __init__(self, uow: UserUnitOfWorkInterface):
self.uow = uow

def create(
def _create(
self, user: UserCreateInputDto
) -> Union[ResponseSuccess, ResponseFailure]:
try:
Expand Down Expand Up @@ -48,7 +49,7 @@ def create(
except Exception as exc:
return ResponseFailure(ResponseTypes.SYSTEM_ERROR, exc)

def authenticate_user(self, user: UserLoginInputDto) -> Union[UserOutputDto, bool]:
def _authenticate_user(self, user: UserLoginInputDto) -> Union[UserOutputDto, bool]:
with self.uow:
user_ = self.uow.users.get_by_email(user.email)
if not user_ or not Hasher.verify_password(
Expand Down
4 changes: 2 additions & 2 deletions src/jobboard/configurator/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
UserSqlAlchemyUnitOfWork,
)
from src.jobboard.adapters.use_cases.jobs import JobsService
from src.jobboard.domain.ports.user_service import UserService
from src.jobboard.adapters.use_cases.users import UsersService
from src.jobboard.configurator import config


Expand Down Expand Up @@ -35,7 +35,7 @@ class Container(containers.DeclarativeContainer):
)

user_service = providers.Factory(
UserService,
UsersService,
uow=user_uow,
)

Expand Down
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion src/jobboard/domain/ports/unit_of_work.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import abc

from src.jobboard.domain.ports import messagebus, repository
from src.jobboard.domain.ports import repository
from src.jobboard.domain.ports.common import messagebus


class UserUnitOfWorkInterface(abc.ABC):
Expand Down
11 changes: 5 additions & 6 deletions src/jobboard/domain/ports/use_cases/jobs.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import abc
from typing import Union

from src.jobboard.domain.ports.responses import ResponseFailure, ResponseSuccess
from src.jobboard.domain.ports.common.responses import ResponseFailure, ResponseSuccess
from src.jobboard.domain.ports.unit_of_work import JobUnitOfWorkInterface
from src.jobboard.domain.schemas.jobs import JobCreateInputDto


class JobsServiceInterface(abc.ABC):

@abc.abstractmethod
def __init__(self, uow: JobUnitOfWorkInterface):
self.uow = uow

def create(
self, job: JobCreateInputDto, owner_id: int
self, job: JobCreateInputDto, owner_id: int
) -> Union[ResponseFailure, ResponseSuccess]:
return self._create(job, owner_id)

Expand All @@ -24,7 +23,7 @@ def list_jobs(self) -> ResponseSuccess:
return self._list_jobs()

def update_job_by_id(
self, id_: int, job: JobCreateInputDto, owner_id: int
self, id_: int, job: JobCreateInputDto, owner_id: int
) -> Union[ResponseFailure, ResponseSuccess]:
return self._update_job_by_id(id_, job, owner_id)

Expand All @@ -36,7 +35,7 @@ def search_job(self, query: str) -> ResponseSuccess:

@abc.abstractmethod
def _create(
self, job: JobCreateInputDto, owner_id: int
self, job: JobCreateInputDto, owner_id: int
) -> Union[ResponseFailure, ResponseSuccess]:
raise NotImplementedError

Expand All @@ -50,7 +49,7 @@ def _list_jobs(self) -> ResponseSuccess:

@abc.abstractmethod
def _update_job_by_id(
self, id_: int, job: JobCreateInputDto, owner_id: int
self, id_: int, job: JobCreateInputDto, owner_id: int
) -> Union[ResponseFailure, ResponseSuccess]:
raise NotImplementedError

Expand Down
34 changes: 34 additions & 0 deletions src/jobboard/domain/ports/use_cases/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import abc
from typing import Union

from src.jobboard.domain.ports.common.responses import ResponseFailure, ResponseSuccess
from src.jobboard.domain.ports.unit_of_work import UserUnitOfWorkInterface
from src.jobboard.domain.schemas.users import (
UserCreateInputDto,
UserLoginInputDto,
UserOutputDto,
)


class UsersServiceInterface(abc.ABC):
@abc.abstractmethod
def __init__(self, uow: UserUnitOfWorkInterface):
self.uow = uow

def create(
self, user: UserCreateInputDto
) -> Union[ResponseSuccess, ResponseFailure]:
return self._create(user)

def authenticate_user(self, user: UserLoginInputDto) -> Union[UserOutputDto, bool]:
return self._authenticate_user(user)

@abc.abstractmethod
def _create(
self, user: UserCreateInputDto
) -> Union[ResponseSuccess, ResponseFailure]:
raise NotImplementedError

@abc.abstractmethod
def _authenticate_user(self, user: UserLoginInputDto) -> Union[UserOutputDto, bool]:
raise NotImplementedError
4 changes: 2 additions & 2 deletions tests/fake_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
UserSqlAlchemyUnitOfWork,
)
from src.jobboard.adapters.use_cases.jobs import JobsService
from src.jobboard.domain.ports.user_service import UserService
from src.jobboard.adapters.use_cases.users import UsersService


class Container(containers.DeclarativeContainer):
Expand Down Expand Up @@ -35,7 +35,7 @@ class Container(containers.DeclarativeContainer):
)

fake_user_service = providers.Factory(
UserService,
UsersService,
uow=user_uow,
)

Expand Down
6 changes: 3 additions & 3 deletions tests/utils/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from fastapi import Depends
from fastapi.testclient import TestClient

from src.jobboard.configurator.hashing import Hasher
from src.jobboard.domain.model.model import user_model_factory
from src.jobboard.domain.ports.user_service import UserService
from src.jobboard.domain.ports.use_cases.users import UsersServiceInterface
from src.jobboard.domain.schemas.users import UserCreateInputDto
from src.jobboard.configurator.hashing import Hasher
from tests.fake_container import Container


Expand All @@ -27,7 +27,7 @@ def user_authentication_headers(
def authentication_token_from_email(
client: TestClient,
email: str,
user_service: UserService = Depends(Provide[Container.fake_user_service]),
user_service: UsersServiceInterface = Depends(Provide[Container.fake_user_service]),
):
"""
Return a valid token for the user with given email.
Expand Down

0 comments on commit d4b7c03

Please sign in to comment.