Skip to content
Prev Previous commit
Next Next commit
feat: TT-401 validated request create time entry
  • Loading branch information
ararcos committed Nov 17, 2021
commit 1b747f2ad8f4bd53da2865e7ac1ee925ff083f27
12 changes: 6 additions & 6 deletions V2/tests/api/azure/time_entry_azure_endpoints_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ def test__time_entry_azure_endpoint__creates_an_time_entry__when_time_entry_has_
time_entries._create_time_entry._JSON_PATH = tmp_directory

time_entry_body = {
"id" : None,
"start_date" : Faker().date(),
"owner_id" : Faker().random_int(),
"id": None,
"start_date": Faker().date(),
"owner_id": Faker().random_int(),
"description": Faker().sentence(),
"activity_id" : Faker().random_int(),
"activity_id": Faker().random_int(),
"uri": "http://timetracker.com",
"technologies" : ["jira","git"],
"technologies": ["jira", "git"],
"end_date": Faker().date(),
"deleted": Faker().random_int(),
"deleted": False,
"timezone_offset": "300",
"project_id": Faker().random_int(),
}
Expand Down
1 change: 1 addition & 0 deletions V2/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# flake8: noqa
from fixtures import _activity_factory, _create_fake_dao, _create_fake_database
from fixtures import _time_entry_factory
32 changes: 32 additions & 0 deletions V2/tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,35 @@ def _create_fake_dao() -> domain.ActivitiesDao:
def _create_fake_database() -> domain.ActivitiesDao:
db_fake = DB('sqlite:///:memory:')
return db_fake


@pytest.fixture(name='time_entry_factory')
def _time_entry_factory() -> TimeEntry:
def _make_time_entry(
id=Faker().random_int(),
start_date=Faker().date(),
owner_id=Faker().random_int(),
description=Faker().sentence(),
activity_id=Faker().random_int(),
uri="http://time-tracker.com",
technologies=["jira", "git"],
end_date=Faker().date(),
deleted=Faker().random_int(),
timezone_offset="300",
project_id=Faker().random_int(),
):
time_entry = TimeEntry(
id=id,
start_date=start_date,
owner_id=owner_id,
description=description,
activity_id=activity_id,
uri=uri,
technologies=technologies,
end_date=end_date,
deleted=deleted,
timezone_offset=timezone_offset,
project_id=project_id,
)
return time_entry
return _make_time_entry
20 changes: 8 additions & 12 deletions V2/tests/integration/daos/time_entries_dao.test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,17 @@ def test_create_time_entry__returns_an_time_entry_dto__when_create_an_time_entry

time_entries_json_dao = TimeEntriesJsonDao(Faker().file_path())
time_entry_data = {
"id" : None,
"start_date" : Faker().date(),
"owner_id" : Faker().random_int(),
"id": None,
"start_date": Faker().date(),
"owner_id": Faker().random_int(),
"description": Faker().sentence(),
"activity_id" : Faker().random_int(),
"uri": "http://hola.com",
"technologies" : ["jira","git"],
"activity_id": Faker().random_int(),
"uri": "http://timetracker.com",
"technologies": ["jira", "git"],
"end_date": Faker().date(),
"deleted": Faker().random_int(),
"timezone_offset": "UTC-5",
"deleted": False,
"timezone_offset": "300",
"project_id": Faker().random_int(),
}
result = time_entries_json_dao.create(time_entry_data)
assert result == TimeEntry(**time_entry_data)




3 changes: 2 additions & 1 deletion V2/tests/unit/services/time_entry_service_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from time_tracker.time_entries._domain import TimeEntryService


def test__create_time_entries__uses_the_time_entry_dao__to_create_an_time_entry(mocker):
expected_time_entry = mocker.Mock()
time_entry_dao = mocker.Mock(
Expand All @@ -12,4 +13,4 @@ def test__create_time_entries__uses_the_time_entry_dao__to_create_an_time_entry(
actual_time_entry = time_entry_service.create(Faker().pydict())

assert time_entry_dao.create.called
assert expected_time_entry == actual_time_entry
assert expected_time_entry == actual_time_entry
8 changes: 3 additions & 5 deletions V2/tests/unit/use_cases/time_entries_use_case_test.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
from faker import Faker

from pytest_mock import MockFixture

from time_tracker.time_entries._domain import _use_cases


def test__create_time_entry_function__uses_the_time_entries_service__to_create_time_entry(
mocker: MockFixture,
mocker: MockFixture, time_entry_factory
):
expected_time_entry = mocker.Mock()
time_entry_service = mocker.Mock(
create=mocker.Mock(return_value=expected_time_entry)
)

time_entry_use_case = _use_cases.CreateTimeEntryUseCase(time_entry_service)
actual_time_entry = time_entry_use_case.create_time_entry(Faker().pydict())
actual_time_entry = time_entry_use_case.create_time_entry(time_entry_factory())

assert time_entry_service.create.called
assert expected_time_entry == actual_time_entry

1 change: 1 addition & 0 deletions V2/time_tracker/time_entries/_application/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# flake8: noqa
from ._time_entries import create_time_entry
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# flake8: noqa
from ._create_time_entry import create_time_entry
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,59 @@
from ... import _infrastructure

_JSON_PATH = (
'time_entries/_infrastructure/_data_persistence/time_entries_data.json'
'time_tracker/time_entries/_infrastructure/_data_persistence/time_entries_data.json'
)


def create_time_entry(req: func.HttpRequest) -> func.HttpResponse:

time_entry_dao = _infrastructure.TimeEntriesJsonDao(_JSON_PATH)
time_entry_service = _domain.TimeEntryService(time_entry_dao)
use_case = _domain._use_cases.CreateTimeEntryUseCase(time_entry_service)

time_entry_data = req.get_json()

time_entry_to_create = _domain.TimeEntry(
id=None,
start_date=time_entry_data["start_date"],
owner_id=time_entry_data["owner_id"],
description=time_entry_data["description"],
activity_id=time_entry_data["activity_id"],
uri=time_entry_data["uri"],
technologies=time_entry_data["technologies"],
end_date=time_entry_data["end_date"],
deleted=time_entry_data["deleted"],
timezone_offset=time_entry_data["timezone_offset"],
project_id=time_entry_data["project_id"]
)

created_time_entry = use_case.create_time_entry(time_entry_to_create.__dict__)

if not created_time_entry:
time_entry_dao = _infrastructure.TimeEntriesJsonDao(_JSON_PATH)
time_entry_service = _domain.TimeEntryService(time_entry_dao)
use_case = _domain._use_cases.CreateTimeEntryUseCase(time_entry_service)

time_entry_data = req.get_json()

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

time_entry_to_create = _domain.TimeEntry(
id=None,
start_date=time_entry_data["start_date"],
owner_id=time_entry_data["owner_id"],
description=time_entry_data["description"],
activity_id=time_entry_data["activity_id"],
uri=time_entry_data["uri"],
technologies=time_entry_data["technologies"],
end_date=time_entry_data["end_date"],
deleted=False,
timezone_offset=time_entry_data["timezone_offset"],
project_id=time_entry_data["project_id"]
)

created_time_entry = use_case.create_time_entry(time_entry_to_create)

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

return func.HttpResponse(
body=json.dumps({'error': 'time_entry could not be created'}),
status_code=500,
body=json.dumps(created_time_entry.__dict__),
status_code=201,
mimetype="application/json"
)

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

def _validate_time_entry(time_entry_data: dict) -> typing.List[str]:
time_entry_fields = [field.name for field in dataclasses.fields(_domain.TimeEntry)]
time_entry_fields.pop(8)
missing_keys = [field for field in time_entry_fields if field not in time_entry_data]
return [
f'The {missing_key} key is missing in the input data'
for missing_key in missing_keys
]
1 change: 1 addition & 0 deletions V2/time_tracker/time_entries/_domain/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# flake8: noqa
from ._entities import TimeEntry
from ._persistence_contracts import TimeEntriesDao
from ._services import TimeEntryService
Expand Down
1 change: 1 addition & 0 deletions V2/time_tracker/time_entries/_domain/_entities/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# flake8: noqa
from ._time_entry import TimeEntry
5 changes: 3 additions & 2 deletions V2/time_tracker/time_entries/_domain/_entities/_time_entry.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from dataclasses import dataclass
from typing import List


@dataclass(frozen=True)
class TimeEntry:
id: int
Expand All @@ -11,6 +12,6 @@ class TimeEntry:
uri: str
technologies: List[str]
end_date: str
deleted: str
deleted: bool
timezone_offset: str
project_id: int
project_id: int
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# flake8: noqa
from ._time_entries_dao import TimeEntriesDao
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from time_tracker.time_entries._domain import TimeEntry


class TimeEntriesDao(abc.ABC):
def create(self, time_entry_data: dict) -> TimeEntry:
pass
pass
1 change: 1 addition & 0 deletions V2/time_tracker/time_entries/_domain/_services/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# flake8: noqa
from ._time_entry import TimeEntryService
11 changes: 6 additions & 5 deletions V2/time_tracker/time_entries/_domain/_services/_time_entry.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from time_tracker.time_entries._domain import TimeEntry, TimeEntriesDao


class TimeEntryService:

def __init__(self, time_entry_dao: TimeEntriesDao):
self.time_entry_dao = time_entry_dao

def create(self, time_entry_data: dict) -> TimeEntry:
return self.time_entry_dao.create(time_entry_data)
def __init__(self, time_entry_dao: TimeEntriesDao):
self.time_entry_dao = time_entry_dao

def create(self, time_entry_data: dict) -> TimeEntry:
return self.time_entry_dao.create(time_entry_data)
3 changes: 2 additions & 1 deletion V2/time_tracker/time_entries/_domain/_use_cases/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from ._create_time_entry_use_case import CreateTimeEntryUseCase
# flake8: noqa
from ._create_time_entry_use_case import CreateTimeEntryUseCase
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from time_tracker.time_entries._domain import TimeEntry, TimeEntryService


class CreateTimeEntryUseCase:

def __init__(self, time_entry_service: TimeEntryService):
self.time_entry_service = time_entry_service
def create_time_entry(self, time_entry_data: dict) -> TimeEntry:
return self.time_entry_service.create(time_entry_data)
def __init__(self, time_entry_service: TimeEntryService):
self.time_entry_service = time_entry_service

def create_time_entry(self, time_entry_data: TimeEntry) -> TimeEntry:
return self.time_entry_service.create(time_entry_data.__dict__)
3 changes: 2 additions & 1 deletion V2/time_tracker/time_entries/_infrastructure/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from ._data_persistence import TimeEntriesJsonDao
# flake8: noqa
from ._data_persistence import TimeEntriesJsonDao
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from ._time_entries_dao import TimeEntriesJsonDao
# flake8: noqa
from ._time_entries_dao import TimeEntriesJsonDao
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

from time_tracker.time_entries._domain import TimeEntriesDao, TimeEntry


class TimeEntriesJsonDao(TimeEntriesDao):

def __init__(self, json_data_file_path: str):
self.json_data_file_path = json_data_file_path
self.time_entry_key = [field.name for field in dataclasses.fields(TimeEntry)]

def create(self, time_entry_data: dict) -> TimeEntry:
def __init__(self, json_data_file_path: str):
self.json_data_file_path = json_data_file_path
self.time_entry_key = [field.name for field in dataclasses.fields(TimeEntry)]

def create(self, time_entry_data: dict) -> TimeEntry:
time_entries = self.__get_time_entries_from_file()
time_entries.append(time_entry_data)

Expand All @@ -22,17 +23,17 @@ def create(self, time_entry_data: dict) -> TimeEntry:
except FileNotFoundError:
print("Can not create activity")

def __get_time_entries_from_file(self) -> typing.List[dict]:
try:
file = open(self.json_data_file_path)
time_entries = json.load(file)
file.close()
def __get_time_entries_from_file(self) -> typing.List[dict]:
try:
file = open(self.json_data_file_path)
time_entries = json.load(file)
file.close()

return time_entries
return time_entries

except FileNotFoundError:
return []
except FileNotFoundError:
return []

def __create_time_entry_dto(self, time_entry: dict) -> TimeEntry:
def __create_time_entry_dto(self, time_entry: dict) -> TimeEntry:
time_entry = {key: time_entry.get(key) for key in self.time_entry_key}
return TimeEntry(**time_entry)
return TimeEntry(**time_entry)
Loading