Skip to content

Commit b4bdd17

Browse files
dsgarcia8scastillo-jp
authored andcommitted
feat: TT-365 Method POST activity and create function serverless
1 parent 6ba8320 commit b4bdd17

File tree

17 files changed

+164
-79
lines changed

17 files changed

+164
-79
lines changed

V2/serverless.yml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,20 @@ functions:
4949

5050
delete_activity:
5151
handler: time_entries/interface.delete_activity
52+
events:
53+
- http: true
54+
x-azure-settings:
55+
methods:
56+
- DELETE
57+
route: activities/{id}
58+
authLevel: anonymous
59+
60+
create_activity:
61+
handler: time_entries/interface.create_activity
5262
events:
5363
- http: true
5464
x-azure-settings:
5565
methods:
56-
- DELETE
57-
route: activities/{id}
58-
authLevel: anonymous
66+
- POST
67+
route: activities/
68+
authLevel: anonymous

V2/tests/api/azure/activity_azure_endpoints_test.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from time_entries._application._activities import (
22
_get_activities,
33
_delete_activity,
4+
_create_activity
45
)
56
import azure.functions as func
67
import json
78
import typing
8-
9+
from faker import Faker
910

1011
def test__activity_azure_endpoint__returns_all_activities(
1112
create_temp_activities,
@@ -57,3 +58,23 @@ def test__activity_azure_endpoint__returns_an_activity_with_inactive_status__whe
5758

5859
assert response.status_code == 200
5960
assert activity_json_data['status'] == 'inactive'
61+
def test__activity_azure_endpoint__creates_an_activity__when_activity_has_all_attributes(
62+
create_temp_activities,
63+
):
64+
activities_json, tmp_directory = create_temp_activities
65+
_create_activity.JSON_PATH = tmp_directory
66+
67+
activity_body = {'id': Faker().uuid4(), 'name': Faker().user_name(), 'description': Faker().sentence(),'deleted': Faker().uuid4() ,'status': 'active', 'tenant_id': Faker().uuid4()}
68+
body = json.dumps(activity_body).encode("utf-8")
69+
req = func.HttpRequest(
70+
method='POST',
71+
body= body,
72+
url='/api/activities/',
73+
)
74+
75+
response = _create_activity.create_activity(req)
76+
activitiy_json_data = response.get_body()
77+
78+
assert response.status_code == 200
79+
assert activitiy_json_data == body
80+

V2/tests/integration/daos/activities_json_dao_test.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ def test_get_all__returns_an_empty_list__when_doesnt_found_any_activities(
8484

8585
assert result == activities
8686

87+
def test_create_activity__returns_an_activity_dto__when_create_an_activity_that_matches_attributes(create_fake_activities):
88+
create_fake_activities([])
89+
90+
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
91+
activity_data = {
92+
"name": "test_name",
93+
"description": "test_description",
94+
"tenant_id": "test_tenant_id",
95+
"id": "test_id",
96+
"deleted": "test_deleted",
97+
"status": "test_status",
98+
}
99+
result = activities_json_dao.create_activity(activity_data)
100+
assert result == Activity(**activity_data)
87101

88102
def test_delete__returns_an_activity_with_inactive_status__when_an_activity_matching_its_id_is_found(
89103
create_fake_activities,
@@ -116,4 +130,4 @@ def test_delete__returns_none__when_no_activity_matching_its_id_is_found(
116130

117131
result = activities_json_dao.delete(Faker().uuid4())
118132

119-
assert result is None
133+
assert result is None

V2/tests/unit/services/activity_service_test.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,15 @@ def test__delete_activity__uses_the_activity_dao__to_change_activity_status(
4141

4242
assert activity_dao.delete.called
4343
assert expected_activity == deleted_activity
44+
45+
def test__create_activity__uses_the_activity_dao__to_create_an_activity(mocker):
46+
expected_activity = mocker.Mock()
47+
activity_dao = mocker.Mock(
48+
create_activity=mocker.Mock(return_value=expected_activity)
49+
)
50+
activity_service = ActivityService(activity_dao)
51+
52+
actual_activity = activity_service.create_activity(Faker().pydict())
53+
54+
assert activity_dao.create_activity.called
55+
assert expected_activity == actual_activity

V2/tests/unit/use_cases/activities_use_case_test.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ def test__get_activity_by_id_function__uses_the_activity_service__to_retrieve_ac
3535
assert activity_service.get_by_id.called
3636
assert expected_activity == actual_activity
3737

38+
def test__create_activity_function__uses_the_activities_service__to_create_activity(
39+
mocker: MockFixture,
40+
):
41+
expected_activity = mocker.Mock()
42+
activity_service = mocker.Mock(
43+
create_activity=mocker.Mock(return_value=expected_activity)
44+
)
45+
46+
activity_use_case = _use_cases.CreateActivityUseCase(activity_service)
47+
actual_activity = activity_use_case.create_activity(fake.pydict())
48+
49+
assert activity_service.create_activity.called
50+
assert expected_activity == actual_activity
3851

3952
def test__delete_activity_function__uses_the_activity_service__to_change_activity_status(
4053
mocker: MockFixture,
@@ -48,4 +61,4 @@ def test__delete_activity_function__uses_the_activity_service__to_change_activit
4861
deleted_activity = activity_use_case.delete_activity(fake.uuid4())
4962

5063
assert activity_service.delete.called
51-
assert expected_activity == deleted_activity
64+
assert expected_activity == deleted_activity
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
from ._activities import get_activities
2-
from ._activities import delete_activity
1+
from ._activities import get_activities, create_activity, delete_activity
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from ._get_activities import get_activities
22
from ._delete_activity import delete_activity
3+
from ._create_activity import create_activity
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from time_entries._infrastructure import ActivitiesJsonDao
2+
from time_entries._domain import ActivityService, _use_cases, Activity
3+
4+
import azure.functions as func
5+
import json
6+
import logging
7+
import dataclasses
8+
9+
10+
JSON_PATH = (
11+
12+
'::WqV2/time_entries/_infrastructure/_data_persistence/activities_data.json'
13+
)
14+
15+
16+
17+
def create_activity(req: func.HttpRequest) -> func.HttpResponse:
18+
logging.info(
19+
'Python HTTP trigger function processed a request to create an activity.'
20+
)
21+
activity_data = req.get_json()
22+
status_code = 200
23+
if _validate_activity(activity_data):
24+
response = _create_activity(activity_data)
25+
else:
26+
status_code = 404
27+
response = b'Not possible to create activity, attributes are not correct '
28+
29+
return func.HttpResponse(
30+
body=response, status_code=status_code, mimetype="application/json"
31+
)
32+
33+
def _create_activity(activity_data: dict) -> str:
34+
activity_use_case = _use_cases.CreateActivityUseCase(
35+
_create_activity_service(JSON_PATH)
36+
)
37+
activity = activity_use_case.create_activity(activity_data)
38+
return json.dumps(activity.__dict__) if activity else b'Not Found'
39+
40+
def _validate_activity(activity_data: dict) -> bool:
41+
activity_keys = [field.name for field in dataclasses.fields(Activity)]
42+
new_activity_keys = list(activity_data.keys())
43+
return all(map(lambda key: key in activity_keys, new_activity_keys)) and len(activity_keys) == len(new_activity_keys)
44+
45+
def _create_activity_service(path: str):
46+
activity_json = ActivitiesJsonDao(path)
47+
return ActivityService(activity_json)
48+
49+

V2/time_entries/_domain/_persistence_contracts/_activities_dao.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ def get_by_id(self, id: str) -> Activity:
1212
def get_all(self) -> typing.List[Activity]:
1313
pass
1414

15+
@abc.abstractmethod
16+
def create_activity(self, activity_data: dict) -> Activity:
17+
pass
18+
1519
@abc.abstractmethod
1620
def delete(self, id: str) -> Activity:
17-
pass
21+
pass

V2/time_entries/_domain/_services/_activity.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ def get_all(self) -> typing.List[Activity]:
1414

1515
def delete(self, activity_id: str) -> Activity:
1616
return self.activities_dao.delete(activity_id)
17+
18+
def create_activity(self, activity_data: dict) -> Activity:
19+
return self.activities_dao.create_activity(activity_data)

0 commit comments

Comments
 (0)