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
reactor: TT-407 rebase with master - DELETE
  • Loading branch information
mandres2015 committed Nov 26, 2021
commit 44d5392be6c70186aa028a872498d150f2624788
37 changes: 24 additions & 13 deletions V2/serverless.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
service: azure-time-tracker

frameworkVersion: "2"
frameworkVersion: '2'

provider:
name: azure
Expand All @@ -23,18 +23,18 @@ plugins:

package:
patterns:
- "!env/**"
- "!.env/**"
- "!local.settings.json"
- "!.vscode/**"
- "!__pycache__/**"
- "!node_modules/**"
- "!.python_packages/**"
- "!.funcignore"
- "!package.json"
- "!package-lock.json"
- "!.gitignore"
- "!.git/**"
- '!env/**'
- '!.env/**'
- '!local.settings.json'
- '!.vscode/**'
- '!__pycache__/**'
- '!node_modules/**'
- '!.python_packages/**'
- '!.funcignore'
- '!package.json'
- '!package-lock.json'
- '!.gitignore'
- '!.git/**'

functions:
get_activities:
Expand Down Expand Up @@ -117,6 +117,16 @@ functions:
route: time-entries/{id}
authLevel: anonymous

get_latest_time_entry:
handler: time_tracker/time_entries/interface.get_latest_entries
events:
- http: true
x-azure-settings:
methods:
- GET
route: time-entries/latest
authLevel: anonymous

create_customer:
handler: time_tracker/customers/interface.create_customer
events:
Expand Down Expand Up @@ -165,4 +175,5 @@ functions:
methods:
- POST
route: projects/

authLevel: anonymous
39 changes: 39 additions & 0 deletions V2/tests/api/azure/time_entry_azure_endpoints_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,42 @@ def test__update_time_entries_azure_endpoint__returns_a_status_code_400__when_ti

assert response.status_code == 400
assert response.get_body() == b'Incorrect time entry body'


def test__get_latest_entries_azure_endpoint__returns_a_list_of_latest_time_entries__when_an_owner_id_match(
test_db, time_entry_factory, insert_time_entry, insert_activity, activity_factory,
):
inserted_activity = insert_activity(activity_factory(), test_db).__dict__
time_entry_body = time_entry_factory(activity_id=inserted_activity["id"], technologies="[jira,sql]")
inserted_time_entry = insert_time_entry(time_entry_body, test_db)

req = func.HttpRequest(
method='GET',
body=None,
url=TIME_ENTRY_URL+"latest/",
params={"owner_id": inserted_time_entry["owner_id"]},
)

response = azure_time_entries._get_latest_entries.get_latest_entries(req)
time_entry_json_data = json.loads(response.get_body().decode("utf-8"))

assert response.status_code == 200
assert time_entry_json_data == [inserted_time_entry]


def test__get_latest_entries_azure_endpoint__returns_No_time_entries_found__when_recieve_an_invalid_owner_id(
test_db, insert_activity, activity_factory,
):
insert_activity(activity_factory(), test_db)

req = func.HttpRequest(
method='GET',
body=None,
url=TIME_ENTRY_URL+"latest/",
params={"owner_id": Faker().pyint()},
)

response = azure_time_entries._get_latest_entries.get_latest_entries(req)

assert response.status_code == 404
assert response.get_body() == b'No time entries found'
28 changes: 27 additions & 1 deletion V2/tests/integration/daos/time_entries_dao_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def test_update__returns_an_time_entry_dto__when_found_one_time_entry_to_update(


def test_update__returns_none__when_doesnt_found_one_time_entry_to_update(
test_db, create_fake_dao, time_entry_factory, insert_activity, activity_factory
test_db, create_fake_dao, time_entry_factory, insert_activity, activity_factory
):
dao = create_fake_dao(test_db)
inserted_activity = insert_activity(activity_factory(), dao.db)
Expand Down Expand Up @@ -153,3 +153,29 @@ def test__get_by_id__returns_none__when_no_time_entry_matches_by_id(
time_entry = dao.get_by_id(Faker().pyint())

assert time_entry is None


def test_get_latest_entries__returns_a_list_of_latest_time_entries__when_an_owner_id_match(
create_fake_dao, time_entry_factory, insert_activity, activity_factory, test_db
):
dao = create_fake_dao(test_db)
inserted_activity = insert_activity(activity_factory(), dao.db)
time_entry_to_insert = time_entry_factory(
activity_id=inserted_activity.id,
technologies="[jira,sql]")
inserted_time_entry = dao.create(time_entry_to_insert)

result = dao.get_latest_entries(int(inserted_time_entry.owner_id))

assert result == [inserted_time_entry.__dict__]


def test_get_latest_entries__returns_None__when_an_owner_id_is_not_found(
create_fake_dao, test_db, insert_activity, activity_factory
):
dao = create_fake_dao(test_db)
insert_activity(activity_factory(), dao.db)

result = dao.get_latest_entries(Faker().pyint())

assert result is None
16 changes: 16 additions & 0 deletions V2/tests/unit/services/time_entry_service_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from faker import Faker

from time_tracker.time_entries._domain import TimeEntryService
from faker import Faker


def test__create_time_entries__uses_the_time_entry_dao__to_create_an_time_entry(mocker, time_entry_factory):
Expand Down Expand Up @@ -72,3 +73,18 @@ def test__get_by_id__uses_the_time_entry_dao__to_retrieve_one_time_entry(mocker)

assert time_entry_dao.get_by_id.called
assert expected_time_entry == actual_time_entry


def test__get_latest_entries__uses_the_time_entry_dao__to_get_last_entries(
mocker,
):
expected_latest_time_entries = mocker.Mock()
time_entry_dao = mocker.Mock(
get_latest_entries=mocker.Mock(return_value=expected_latest_time_entries)
)

time_entry_service = TimeEntryService(time_entry_dao)
latest_time_entries = time_entry_service.get_latest_entries(Faker().pyint(), Faker().pyint())

assert expected_latest_time_entries == latest_time_entries
assert time_entry_dao.get_latest_entries.called
13 changes: 13 additions & 0 deletions V2/tests/unit/use_cases/time_entries_use_case_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,16 @@ def test__get_time_entry_by_id_function__uses_the_time_entry_service__to_retriev

assert time_entry_service.get_by_id.called
assert expected_time_entries == actual_time_entry


def test__get_latest_entries_function__uses_the_time_entry_service__to_get_last_entries(
mocker: MockFixture,
):
expected_latest_time_entries = mocker.Mock()
time_entry_service = mocker.Mock(get_latest_entries=mocker.Mock(return_value=expected_latest_time_entries))

time_entry_use_case = _use_cases.GetLastestTimeEntryUseCase(time_entry_service)
latest_time_entries = time_entry_use_case.get_latest_entries(Faker().pyint(), Faker().pyint())

assert time_entry_service.get_latest_entries.called
assert expected_latest_time_entries == latest_time_entries
1 change: 1 addition & 0 deletions V2/time_tracker/time_entries/_application/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from ._time_entries import delete_time_entry
from ._time_entries import update_time_entry
from ._time_entries import get_time_entries
from ._time_entries import get_latest_entries
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from ._delete_time_entry import delete_time_entry
from ._update_time_entry import update_time_entry
from ._get_time_entries import get_time_entries
from ._get_latest_entries import get_latest_entries
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import json

import azure.functions as func

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


def get_latest_entries(req: func.HttpRequest) -> func.HttpResponse:
database = DB()
time_entry_dao = _infrastructure.TimeEntriesSQLDao(database)
time_entry_service = _domain.TimeEntryService(time_entry_dao)
use_case = _domain._use_cases.GetLastestTimeEntryUseCase(time_entry_service)

try:
owner_id = req.params.get("owner_id")
limit = req.params.get("limit")

if not owner_id:
return func.HttpResponse(
body="No owner id found",
status_code=404,
mimetype="application/json"
)

time_entries = use_case.get_latest_entries(int(owner_id), int(limit) if limit and int(limit) > 0 else None)

if not time_entries or len(time_entries) == 0:
return func.HttpResponse(
body="No time entries found",
status_code=404,
mimetype="application/json"
)

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

except ValueError:
return func.HttpResponse(
body=b"Invalid Format ID",
status_code=400,
mimetype="application/json"
)
3 changes: 2 additions & 1 deletion V2/time_tracker/time_entries/_domain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
DeleteTimeEntryUseCase,
UpdateTimeEntryUseCase,
GetTimeEntriesUseCase,
GetTimeEntryUseCase
GetTimeEntryUseCase,
GetLastestTimeEntryUseCase,
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ def delete(self, id: int) -> TimeEntry:
def update(self, id: int, new_time_entry: dict) -> TimeEntry:
pass

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

@abc.abstractmethod
def get_all(self) -> typing.List[TimeEntry]:
pass

@abc.abstractmethod
def get_latest_entries(self, owner_id: int, limit: int) -> typing.List[TimeEntry]:
pass
4 changes: 4 additions & 0 deletions V2/time_tracker/time_entries/_domain/_services/_time_entry.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import typing

from time_tracker.time_entries._domain import TimeEntry, TimeEntriesDao
import typing


class TimeEntryService:
Expand All @@ -21,3 +22,6 @@ def get_by_id(self, id: int) -> TimeEntry:

def get_all(self) -> typing.List[TimeEntry]:
return self.time_entry_dao.get_all()

def get_latest_entries(self, owner_id: int, limit: int) -> typing.List[TimeEntry]:
return self.time_entry_dao.get_latest_entries(owner_id, limit)
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
from ._update_time_entry_use_case import UpdateTimeEntryUseCase
from ._get_time_entry_use_case import GetTimeEntriesUseCase
from ._get_time_entry_by_id_use_case import GetTimeEntryUseCase
from ._get_latest_entries_use_case import GetLastestTimeEntryUseCase
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from time_tracker.time_entries._domain import TimeEntry, TimeEntryService
import typing


class GetLastestTimeEntryUseCase:

def __init__(self, time_entry_service: TimeEntryService):
self.time_entry_service = time_entry_service

def get_latest_entries(self, owner_id: int, limit: int) -> typing.List[TimeEntry]:
return self.time_entry_service.get_latest_entries(owner_id, limit)
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,17 @@ def __create_time_entry_dto(self, time_entry: dict) -> domain.TimeEntry:
"end_date": str(time_entry.get("end_date"))})
time_entry = {key: time_entry.get(key) for key in self.time_entry_key}
return domain.TimeEntry(**time_entry)

def get_latest_entries(self, owner_id: int, limit: int = 20) -> typing.List[domain.TimeEntry]:
query = (
self.time_entry.select()
.where(sqlalchemy.and_(
self.time_entry.c.owner_id == owner_id,
self.time_entry.c.deleted.is_(False)
))
.order_by(self.time_entry.c.start_date.desc())
.limit(limit)
)
time_entries_data = self.db.get_session().execute(query)
list_time_entries = [dict(entry) for entry in time_entries_data]
return list_time_entries if len(list_time_entries) > 0 else None
1 change: 1 addition & 0 deletions V2/time_tracker/time_entries/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from ._application import delete_time_entry
from ._application import update_time_entry
from ._application import get_time_entries
from ._application import get_latest_entries