Skip to content

Commit 6c3687b

Browse files
feat: TT-365 / TT-369 POST V2 Activity (#329)
* feat: TT-365 Method POST activity and create function serverless * fix: TT-365 resolve comments * fix: TT-365 format code Co-authored-by: Sandro Castillo <[email protected]>
1 parent 3c9ac26 commit 6c3687b

File tree

17 files changed

+175
-5
lines changed

17 files changed

+175
-5
lines changed

V2/serverless.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ functions:
6363
- http: true
6464
x-azure-settings:
6565
methods:
66-
- PUT
66+
- PUT
6767
route: activities/{id}
68+
authLevel: anonymous
69+
70+
create_activity:
71+
handler: time_entries/interface.create_activity
72+
events:
73+
- http: true
74+
x-azure-settings:
75+
methods:
76+
- POST
77+
route: activities/
6878
authLevel: anonymous

V2/tests/api/azure/activity_azure_endpoints_test.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,22 @@ def test__update_activity_azure_endpoint__returns_an_activity__when_found_an_act
8080

8181
assert response.status_code == 200
8282
assert activitiy_json_data == json.dumps(new_activity)
83+
84+
def test__activity_azure_endpoint__creates_an_activity__when_activity_has_all_attributes(
85+
create_temp_activities,
86+
):
87+
activities_json, tmp_directory = create_temp_activities
88+
activities._create_activity._JSON_PATH = tmp_directory
89+
90+
activity_body = {'id': None, 'name': Faker().user_name(), 'description': Faker().sentence(),'deleted': Faker().uuid4() ,'status': 'active', 'tenant_id': Faker().uuid4()}
91+
body = json.dumps(activity_body).encode("utf-8")
92+
req = func.HttpRequest(
93+
method='POST',
94+
body= body,
95+
url=ACTIVITY_URL,
96+
)
97+
98+
response = activities.create_activity(req)
99+
activitiy_json_data = response.get_body()
100+
assert response.status_code == 201
101+
assert activitiy_json_data == body

V2/tests/integration/daos/activities_json_dao_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,18 @@ def test_update__returns_none__when_doesnt_found_one_activity_to_update(
132132
result = activities_json_dao.update('', activity_data)
133133

134134
assert result == None
135+
136+
def test_create_activity__returns_an_activity_dto__when_create_an_activity_that_matches_attributes(create_fake_activities):
137+
create_fake_activities([])
138+
139+
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
140+
activity_data = {
141+
"name": "test_name",
142+
"description": "test_description",
143+
"tenant_id": "test_tenant_id",
144+
"id": "test_id",
145+
"deleted": "test_deleted",
146+
"status": "test_status",
147+
}
148+
result = activities_json_dao.create_activity(activity_data)
149+
assert result == Activity(**activity_data)

V2/tests/unit/services/activity_service_test.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,15 @@ def test__update_activity__uses_the_activity_dao__to_update_one_activity(
5858

5959
assert activity_dao.update.called
6060
assert expected_activity == updated_activity
61+
62+
def test__create_activity__uses_the_activity_dao__to_create_an_activity(mocker):
63+
expected_activity = mocker.Mock()
64+
activity_dao = mocker.Mock(
65+
create_activity=mocker.Mock(return_value=expected_activity)
66+
)
67+
activity_service = ActivityService(activity_dao)
68+
69+
actual_activity = activity_service.create_activity(Faker().pydict())
70+
71+
assert activity_dao.create_activity.called
72+
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
@@ -36,6 +36,20 @@ def test__get_activity_by_id_function__uses_the_activity_service__to_retrieve_ac
3636
assert expected_activity == actual_activity
3737

3838

39+
def test__create_activity_function__uses_the_activities_service__to_create_activity(
40+
mocker: MockFixture,
41+
):
42+
expected_activity = mocker.Mock()
43+
activity_service = mocker.Mock(
44+
create_activity=mocker.Mock(return_value=expected_activity)
45+
)
46+
47+
activity_use_case = _use_cases.CreateActivityUseCase(activity_service)
48+
actual_activity = activity_use_case.create_activity(fake.pydict())
49+
50+
assert activity_service.create_activity.called
51+
assert expected_activity == actual_activity
52+
3953
def test__delete_activity_function__uses_the_activity_service__to_change_activity_status(
4054
mocker: MockFixture,
4155
):
@@ -50,7 +64,6 @@ def test__delete_activity_function__uses_the_activity_service__to_change_activit
5064
assert activity_service.delete.called
5165
assert expected_activity == deleted_activity
5266

53-
5467
def test__update_activity_function__uses_the_activities_service__to_update_an_activity(
5568
mocker: MockFixture,
5669
):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from ._activities import get_activities
22
from ._activities import delete_activity
33
from ._activities import update_activity
4+
from ._activities import create_activity
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from ._get_activities import get_activities
22
from ._delete_activity import delete_activity
33
from ._update_activity import update_activity
4+
from ._create_activity import create_activity
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import json
2+
import logging
3+
import dataclasses
4+
import typing
5+
6+
import azure.functions as func
7+
8+
from ... import _domain
9+
from ... import _infrastructure
10+
11+
_JSON_PATH = (
12+
'time_entries/_infrastructure/_data_persistence/activities_data.json'
13+
)
14+
15+
16+
def create_activity(req: func.HttpRequest) -> func.HttpResponse:
17+
activity_dao = _infrastructure.ActivitiesJsonDao(_JSON_PATH)
18+
activity_service = _domain.ActivityService(activity_dao)
19+
use_case = _domain._use_cases.CreateActivityUseCase(activity_service)
20+
21+
22+
activity_data = req.get_json()
23+
24+
25+
validation_errors = _validate_activity(activity_data)
26+
if validation_errors:
27+
return func.HttpResponse(
28+
body=validation_errors, status_code=400, mimetype="application/json"
29+
)
30+
31+
32+
activity_to_create = _domain.Activity(
33+
id= None,
34+
name=activity_data['name'],
35+
description=activity_data['description'],
36+
status=activity_data['status'],
37+
deleted=activity_data['deleted'],
38+
tenant_id=activity_data['tenant_id']
39+
)
40+
41+
42+
created_activity = use_case.create_activity(activity_to_create.__dict__)
43+
if not create_activity:
44+
return func.HttpResponse(
45+
body={'error': 'activity could not be created'},
46+
status_code=500,
47+
mimetype="application/json",
48+
)
49+
return func.HttpResponse(
50+
body=json.dumps(created_activity.__dict__),
51+
status_code=201,
52+
mimetype="application/json"
53+
)
54+
55+
56+
def _validate_activity(activity_data: dict) -> typing.List[str]:
57+
activity_fields = [field.name for field in dataclasses.fields(_domain.Activity)]
58+
missing_keys = [field for field in activity_fields if field not in activity_data]
59+
return [
60+
f'The {missing_key} key is missing in the input data'
61+
for missing_key in missing_keys
62+
]

V2/time_entries/_domain/_persistence_contracts/_activities_dao.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,11 @@ def delete(self, id: str) -> Activity:
1919
@abc.abstractmethod
2020
def update(self, id: str, new_activity: dict) -> Activity:
2121
pass
22+
23+
@abc.abstractmethod
24+
def create_activity(self, activity_data: dict) -> Activity:
25+
pass
26+
27+
@abc.abstractmethod
28+
def delete(self, id: str) -> Activity:
29+
pass

V2/time_entries/_domain/_services/_activity.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ def delete(self, activity_id: str) -> Activity:
1717

1818
def update(self, activity_id: str, new_activity: dict) -> Activity:
1919
return self.activities_dao.update(activity_id, new_activity)
20+
21+
def create_activity(self, activity_data: dict) -> Activity:
22+
return self.activities_dao.create_activity(activity_data)

0 commit comments

Comments
 (0)