Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: TT-417 created CRUD project
  • Loading branch information
ararcos authored and Jobzi committed Nov 25, 2021
commit 237d47e3809dead79ff5e57336bb2e317776789c
42 changes: 40 additions & 2 deletions V2/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ functions:
route: time-entries/{id}
authLevel: anonymous


update_time_entry:
handler: time_tracker/time_entries/interface.update_time_entry
events:
Expand All @@ -117,4 +116,43 @@ functions:
- POST
route: customers/
authLevel: anonymous


get_projects:
handler: time_tracker/projects/interface.get_projects
events:
- http: true
x-azure-settings:
methods:
- GET
route: projects/{id:?}
authLevel: anonymous

delete_project:
handler: time_tracker/projects/interface.delete_project
events:
- http: true
x-azure-settings:
methods:
- DELETE
route: projects/{id}
authLevel: anonymous

update_project:
handler: time_tracker/projects/interface.update_project
events:
- http: true
x-azure-settings:
methods:
- PUT
route: projects/{id}
authLevel: anonymous

create_project:
handler: time_tracker/projects/interface.create_project
events:
- http: true
x-azure-settings:
methods:
- POST
route: projects/
authLevel: anonymous
5 changes: 5 additions & 0 deletions V2/time_tracker/projects/_application/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# flake8: noqa
from ._projects import create_project
from ._projects import delete_project
from ._projects import get_projects
from ._projects import update_project
5 changes: 5 additions & 0 deletions V2/time_tracker/projects/_application/_projects/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# flake8: noqa
from ._create_project import create_project
from ._delete_project import delete_project
from ._get_projects import get_projects
from ._update_project import update_project
62 changes: 62 additions & 0 deletions V2/time_tracker/projects/_application/_projects/_create_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import dataclasses
import json
import typing

import azure.functions as func

from ... import _domain
from ... import _infrastructure
from time_tracker._infrastructure import DB


def create_project(req: func.HttpRequest) -> func.HttpResponse:
database = DB()
project_dao = _infrastructure.ProjectsSQLDao(database)
project_service = _domain.ProjectService(project_dao)
use_case = _domain._use_cases.CreateProjectUseCase(project_service)

project_data = req.get_json()

validation_errors = _validate_project(project_data)
if validation_errors:
return func.HttpResponse(
body=json.dumps(validation_errors), status_code=400, mimetype="application/json"
)

project_to_create = _domain.Project(
id=None,
name=project_data["name"],
description=project_data["description"],
project_type_id=1,
customer_id=project_data["customer_id"],
status=1,
deleted=False
)

created_project = use_case.create_project(project_to_create)

if not created_project:
return func.HttpResponse(
body=json.dumps({'error': 'project could not be created'}),
status_code=500,
mimetype="application/json"
)

return func.HttpResponse(
body=json.dumps(created_project.__dict__),
status_code=201,
mimetype="application/json"
)


def _validate_project(project_data: dict) -> typing.List[str]:
project_fields = [field.name for field in dataclasses.fields(_domain.Project)]
project_fields.pop(6)
project_fields.pop(5)
project_fields.pop(3)
project_fields.pop(0)
missing_keys = [field for field in project_fields if field not in project_data]
return [
f'The {missing_key} key is missing in the input data'
for missing_key in missing_keys
]
36 changes: 36 additions & 0 deletions V2/time_tracker/projects/_application/_projects/_delete_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import json

import azure.functions as func

from ... import _domain
from ... import _infrastructure
from time_tracker._infrastructure import DB


def delete_project(req: func.HttpRequest) -> func.HttpResponse:
project_dao = _infrastructure.ProjectsSQLDao(DB())
project_service = _domain.ProjectService(project_dao)
use_case = _domain._use_cases.DeleteProjectUseCase(project_service)

try:
project_id = int(req.route_params.get("id"))
deleted_project = use_case.delete_project(project_id)
if not deleted_project:
return func.HttpResponse(
body="Not found",
status_code=404,
mimetype="application/json"
)

return func.HttpResponse(
body=json.dumps(deleted_project.__dict__, default=str),
status_code=200,
mimetype="application/json",
)

except ValueError:
return func.HttpResponse(
body=b"Invalid Format ID",
status_code=400,
mimetype="application/json"
)
57 changes: 57 additions & 0 deletions V2/time_tracker/projects/_application/_projects/_get_projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import dataclasses
import json
import typing

import azure.functions as func

from ... import _domain
from ... import _infrastructure
from time_tracker._infrastructure import DB


def get_projects(req: func.HttpRequest) -> func.HttpResponse:
database = DB()
project_dao = _infrastructure.ProjectsSQLDao(database)
project_service = _domain.ProjectService(project_dao)

project_id = req.route_params.get("id")

try:
if project_id:
response = _get_by_id(int(project_id), project_service)
if not response:
return func.HttpResponse(
body="Not found",
status_code=404,
mimetype="application/json"
)
else:
response = _get_all(project_service)

return func.HttpResponse(
body=json.dumps(response, default=str),
status_code=200,
mimetype="application/json",
)

except ValueError:
return func.HttpResponse(
body=b"Invalid format id",
status_code=400,
mimetype="application/json"
)


def _get_by_id(project_id: int, project_service: _domain.ProjectService) -> str:
use_case = _domain._use_cases.GetProjectUseCase(project_service)
project = use_case.get_project_by_id(project_id)

return project.__dict__ if project else None


def _get_all(project_service: _domain.ProjectService) -> typing.List:
use_case = _domain._use_cases.GetProjectsUseCase(project_service)
return [
project.__dict__
for project in use_case.get_projects()
]
55 changes: 55 additions & 0 deletions V2/time_tracker/projects/_application/_projects/_update_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import dataclasses
import json
import typing

import azure.functions as func

from ... import _domain
from ... import _infrastructure
from time_tracker._infrastructure import DB


def update_project(req: func.HttpRequest) -> func.HttpResponse:
database = DB()
project_dao = _infrastructure.ProjectsSQLDao(database)
project_service = _domain.ProjectService(project_dao)
use_case = _domain._use_cases.UpdateProjectUseCase(project_service)

try:
project_id = int(req.route_params.get("id"))
project_data = req.get_json()
status_code = 200

if not _validate_project(project_data):
status_code = 400
response = "Incorrect project body"

response = use_case.update_project(
project_id,
project_data.get("name"),
project_data.get("description"),
project_data.get("customer_id"),
project_data.get("status")
).__dict__

if not update_project:
status_code = 404
response = "Not found"

return func.HttpResponse(
body=json.dumps(response, default=str),
status_code=status_code,
mimetype="application/json",
)

except ValueError:
return func.HttpResponse(
body=b"Invalid Format ID",
status_code=400,
mimetype="application/json"
)


def _validate_project(project_data: dict) -> bool:
project_keys = [field.name for field in dataclasses.fields(_domain.Project)]
return all(key in project_keys for key in project_data.keys())
11 changes: 11 additions & 0 deletions V2/time_tracker/projects/_domain/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# flake8: noqa
from ._entities import Project
from ._persistence_contracts import ProjectsDao
from ._services import ProjectService
from ._use_cases import (
CreateProjectUseCase,
DeleteProjectUseCase,
GetProjectsUseCase,
GetProjectUseCase,
UpdateProjectUseCase
)
2 changes: 2 additions & 0 deletions V2/time_tracker/projects/_domain/_entities/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# flake8: noqa
from ._project import Project
13 changes: 13 additions & 0 deletions V2/time_tracker/projects/_domain/_entities/_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from dataclasses import dataclass
from typing import List


@dataclass(frozen=True)
class Project:
id: str
name: str
description: str
project_type_id: int
customer_id: int
status: int
deleted: bool
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# flake8: noqa
from ._projects_dao import ProjectsDao
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import abc

from .. import Project


class ProjectsDao(abc.ABC):
@abc.abstractmethod
def create(self, time_entry_data: Project) -> Project:
pass

@abc.abstractmethod
def get_all(self) -> Project:
pass

@abc.abstractmethod
def get_by_id(self, id: int) -> Project:
pass

@abc.abstractmethod
def update(self, id: int, name: str, description: str, customer_id: int, status: int) -> Project:
pass

@abc.abstractmethod
def delete(self, id: int) -> Project:
pass
2 changes: 2 additions & 0 deletions V2/time_tracker/projects/_domain/_services/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# flake8: noqa
from ._project import ProjectService
24 changes: 24 additions & 0 deletions V2/time_tracker/projects/_domain/_services/_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import typing

from .. import Project, ProjectsDao


class ProjectService:

def __init__(self, project_dao: ProjectsDao):
self.project_dao = project_dao

def create(self, project_data: Project) -> Project:
return self.project_dao.create(project_data)

def get_all(self) -> typing.List[Project]:
return self.project_dao.get_all()

def get_by_id(self, id: int) -> Project:
return self.project_dao.get_by_id(id)

def update(self, id: int, name: str, description: str, customer_id: int, status: int) -> Project:
return self.project_dao.update(id, name, description, customer_id, status)

def delete(self, id: int) -> Project:
return self.project_dao.delete(id)
6 changes: 6 additions & 0 deletions V2/time_tracker/projects/_domain/_use_cases/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# flake8: noqa
from ._create_project_use_case import CreateProjectUseCase
from ._delete_project_use_case import DeleteProjectUseCase
from ._get_project_by_id_use_case import GetProjectUseCase
from ._get_projects_use_case import GetProjectsUseCase
from ._update_project_use_case import UpdateProjectUseCase
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from .. import Project, ProjectService


class CreateProjectUseCase:

def __init__(self, project_service: ProjectService):
self.project_service = project_service

def create_project(self, project_data: Project) -> Project:
return self.project_service.create(project_data)
Loading