Skip to content

Commit d1413ee

Browse files
committed
feat: 🚧 add query param time-offset to summary endpoint
1 parent 0f389fc commit d1413ee

File tree

8 files changed

+189
-131
lines changed

8 files changed

+189
-131
lines changed

commons/data_access_layer/cosmos_db.py

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import dataclasses
22
import logging
3-
import uuid
4-
from datetime import datetime, timezone
5-
from typing import Callable, List, Dict
3+
from typing import Callable, List
64

75
import azure.cosmos.cosmos_client as cosmos_client
86
import azure.cosmos.exceptions as exceptions
@@ -380,62 +378,7 @@ def init_app(app: Flask) -> None:
380378
cosmos_helper = CosmosDBFacade.from_flask_config(app)
381379

382380

383-
def current_datetime() -> datetime:
384-
return datetime.now(timezone.utc)
385-
386-
387-
def datetime_str(value: datetime) -> str:
388-
if value is not None:
389-
return value.isoformat()
390-
else:
391-
return None
392-
393-
394-
def current_datetime_str() -> str:
395-
return datetime_str(current_datetime())
396-
397-
398381
def generate_uuid4() -> str:
399-
return str(uuid.uuid4())
400-
401-
402-
def get_last_day_of_month(year: int, month: int) -> int:
403-
from calendar import monthrange
404-
405-
return monthrange(year=year, month=month)[1]
406-
407-
408-
def get_current_year() -> int:
409-
return datetime.now().year
410-
411-
412-
def get_current_month() -> int:
413-
return datetime.now().month
414-
415-
416-
def get_current_day() -> int:
417-
return datetime.now().day
418-
419-
420-
def get_date_range_of_month(year: int, month: int) -> Dict[str, str]:
421-
first_day_of_month = 1
422-
start_date = datetime(
423-
year=year, month=month, day=first_day_of_month, tzinfo=timezone.utc
424-
)
425-
426-
last_day_of_month = get_last_day_of_month(year=year, month=month)
427-
end_date = datetime(
428-
year=year,
429-
month=month,
430-
day=last_day_of_month,
431-
hour=23,
432-
minute=59,
433-
second=59,
434-
microsecond=999999,
435-
tzinfo=timezone.utc,
436-
)
382+
from uuid import uuid4
437383

438-
return {
439-
'start_date': datetime_str(start_date),
440-
'end_date': datetime_str(end_date),
441-
}
384+
return str(uuid4())

tests/commons/data_access_layer/cosmos_db_test.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
from dataclasses import dataclass
22
from datetime import timedelta
33
from typing import Callable
4+
from faker import Faker
45

56
import pytest
7+
from pytest import fail
8+
69
from azure.cosmos.exceptions import (
710
CosmosResourceExistsError,
811
CosmosResourceNotFoundError,
912
)
10-
from faker import Faker
11-
from flask_restplus._http import HTTPStatus
12-
from pytest import fail
1313

14+
from commons.data_access_layer.database import EventContext
1415
from commons.data_access_layer.cosmos_db import (
1516
CosmosDBRepository,
1617
CosmosDBModel,
17-
CustomError,
18-
current_datetime,
19-
datetime_str,
2018
)
21-
from commons.data_access_layer.database import EventContext
19+
20+
from utils.time import datetime_str, current_datetime
2221

2322
fake = Faker()
2423
Faker.seed()

tests/time_tracker_api/time_entries/time_entries_model_test.py

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import pytest
44
from faker import Faker
55

6-
from commons.data_access_layer.cosmos_db import current_datetime, datetime_str
6+
from utils.time import datetime_str, current_datetime
77
from commons.data_access_layer.database import EventContext
8-
from time_tracker_api.time_entries.time_entries_model import TimeEntryCosmosDBRepository, TimeEntryCosmosDBModel, \
9-
container_definition
8+
from time_tracker_api.time_entries.time_entries_model import (
9+
TimeEntryCosmosDBRepository,
10+
TimeEntryCosmosDBModel,
11+
container_definition,
12+
)
1013

1114
fake = Faker()
1215

@@ -15,42 +18,60 @@
1518
two_days_ago = current_datetime() - timedelta(days=2)
1619

1720

18-
def create_time_entry(start_date: datetime, end_date: datetime,
19-
owner_id: str, tenant_id: str, event_context: EventContext,
20-
time_entry_repository: TimeEntryCosmosDBRepository) -> TimeEntryCosmosDBModel:
21+
def create_time_entry(
22+
start_date: datetime,
23+
end_date: datetime,
24+
owner_id: str,
25+
tenant_id: str,
26+
event_context: EventContext,
27+
time_entry_repository: TimeEntryCosmosDBRepository,
28+
) -> TimeEntryCosmosDBModel:
2129
data = {
2230
"project_id": fake.uuid4(),
2331
"activity_id": fake.uuid4(),
2432
"description": fake.paragraph(nb_sentences=2),
2533
"start_date": datetime_str(start_date),
2634
"end_date": datetime_str(end_date),
2735
"owner_id": owner_id,
28-
"tenant_id": tenant_id
36+
"tenant_id": tenant_id,
2937
}
3038

31-
created_item = time_entry_repository.create(data, event_context,
32-
mapper=TimeEntryCosmosDBModel)
39+
created_item = time_entry_repository.create(
40+
data, event_context, mapper=TimeEntryCosmosDBModel
41+
)
3342
return created_item
3443

3544

3645
@pytest.mark.parametrize(
3746
'start_date,end_date', [(two_days_ago, yesterday), (now, None)]
3847
)
39-
def test_find_interception_with_date_range_should_find(start_date: datetime,
40-
end_date: datetime,
41-
owner_id: str,
42-
tenant_id: str,
43-
time_entry_repository: TimeEntryCosmosDBRepository):
44-
event_ctx = EventContext(container_definition["id"], "create",
45-
tenant_id=tenant_id, user_id=owner_id)
46-
47-
existing_item = create_time_entry(start_date, end_date, owner_id, tenant_id,
48-
event_ctx, time_entry_repository)
48+
def test_find_interception_with_date_range_should_find(
49+
start_date: datetime,
50+
end_date: datetime,
51+
owner_id: str,
52+
tenant_id: str,
53+
time_entry_repository: TimeEntryCosmosDBRepository,
54+
):
55+
event_ctx = EventContext(
56+
container_definition["id"],
57+
"create",
58+
tenant_id=tenant_id,
59+
user_id=owner_id,
60+
)
61+
62+
existing_item = create_time_entry(
63+
start_date,
64+
end_date,
65+
owner_id,
66+
tenant_id,
67+
event_ctx,
68+
time_entry_repository,
69+
)
4970

5071
try:
51-
result = time_entry_repository.find_interception_with_date_range(datetime_str(yesterday),
52-
datetime_str(now),
53-
owner_id, tenant_id)
72+
result = time_entry_repository.find_interception_with_date_range(
73+
datetime_str(yesterday), datetime_str(now), owner_id, tenant_id
74+
)
5475

5576
assert result is not None
5677
assert len(result) > 0
@@ -59,42 +80,63 @@ def test_find_interception_with_date_range_should_find(start_date: datetime,
5980
time_entry_repository.delete_permanently(existing_item.id, event_ctx)
6081

6182

62-
def test_find_interception_should_ignore_id_of_existing_item(owner_id: str, tenant_id: str,
63-
time_entry_repository: TimeEntryCosmosDBRepository):
64-
event_ctx = EventContext(container_definition["id"], "create", tenant_id=tenant_id, user_id=owner_id)
83+
def test_find_interception_should_ignore_id_of_existing_item(
84+
owner_id: str,
85+
tenant_id: str,
86+
time_entry_repository: TimeEntryCosmosDBRepository,
87+
):
88+
event_ctx = EventContext(
89+
container_definition["id"],
90+
"create",
91+
tenant_id=tenant_id,
92+
user_id=owner_id,
93+
)
6594
start_date = datetime_str(yesterday)
6695
end_date = datetime_str(now)
67-
existing_item = create_time_entry(yesterday, now, owner_id, tenant_id, event_ctx, time_entry_repository)
96+
existing_item = create_time_entry(
97+
yesterday, now, owner_id, tenant_id, event_ctx, time_entry_repository
98+
)
6899
try:
69-
colliding_result = time_entry_repository.find_interception_with_date_range(start_date, end_date,
70-
owner_id, tenant_id)
71-
72-
non_colliding_result = time_entry_repository.find_interception_with_date_range(start_date, end_date,
73-
owner_id, tenant_id,
74-
ignore_id=existing_item.id)
100+
colliding_result = time_entry_repository.find_interception_with_date_range(
101+
start_date, end_date, owner_id, tenant_id
102+
)
103+
104+
non_colliding_result = time_entry_repository.find_interception_with_date_range(
105+
start_date,
106+
end_date,
107+
owner_id,
108+
tenant_id,
109+
ignore_id=existing_item.id,
110+
)
75111

76112
colliding_result is not None
77113
assert any([existing_item.id == item.id for item in colliding_result])
78114

79115
non_colliding_result is not None
80-
assert not any([existing_item.id == item.id for item in non_colliding_result])
116+
assert not any(
117+
[existing_item.id == item.id for item in non_colliding_result]
118+
)
81119
finally:
82120
time_entry_repository.delete_permanently(existing_item.id, event_ctx)
83121

84122

85-
def test_find_running_should_return_running_time_entry(running_time_entry,
86-
time_entry_repository: TimeEntryCosmosDBRepository):
87-
found_time_entry = time_entry_repository.find_running(running_time_entry.tenant_id,
88-
running_time_entry.owner_id)
123+
def test_find_running_should_return_running_time_entry(
124+
running_time_entry, time_entry_repository: TimeEntryCosmosDBRepository
125+
):
126+
found_time_entry = time_entry_repository.find_running(
127+
running_time_entry.tenant_id, running_time_entry.owner_id
128+
)
89129

90130
assert found_time_entry is not None
91131
assert found_time_entry.id == running_time_entry.id
92132
assert found_time_entry.owner_id == running_time_entry.owner_id
93133

94134

95-
def test_find_running_should_not_find_any_item(tenant_id: str,
96-
owner_id: str,
97-
time_entry_repository: TimeEntryCosmosDBRepository):
135+
def test_find_running_should_not_find_any_item(
136+
tenant_id: str,
137+
owner_id: str,
138+
time_entry_repository: TimeEntryCosmosDBRepository,
139+
):
98140
try:
99141
time_entry_repository.find_running(tenant_id, owner_id)
100142
except Exception as e:

tests/time_tracker_api/time_entries/time_entries_namespace_test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
from flask_restplus._http import HTTPStatus
88
from pytest_mock import MockFixture, pytest
99

10-
from commons.data_access_layer.cosmos_db import (
10+
from utils.time import (
11+
get_current_year,
12+
get_current_month,
1113
current_datetime,
1214
current_datetime_str,
13-
get_current_month,
14-
get_current_year,
1515
)
16-
1716
from utils import worked_time
1817

1918
from werkzeug.exceptions import NotFound, UnprocessableEntity, HTTPException

time_tracker_api/time_entries/time_entries_model.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,8 @@
1111
CosmosDBRepository,
1212
CustomError,
1313
CosmosDBModel,
14-
current_datetime_str,
15-
datetime_str,
16-
get_date_range_of_month,
17-
get_current_year,
18-
get_current_month,
19-
get_current_day,
2014
)
15+
2116
from commons.data_access_layer.database import EventContext
2217
from time_tracker_api.activities import activities_model
2318

@@ -28,10 +23,18 @@
2823
create_custom_query_from_str,
2924
add_user_email_to_time_entries,
3025
)
26+
from utils.time import (
27+
datetime_str,
28+
get_current_year,
29+
get_current_month,
30+
get_current_day,
31+
get_date_range_of_month,
32+
current_datetime_str,
33+
)
3134
from utils import worked_time
3235
from utils.worked_time import str_to_datetime
33-
3436
from utils.azure_users import AzureConnection
37+
3538
from time_tracker_api.projects.projects_model import ProjectCosmosDBModel
3639
from time_tracker_api.projects import projects_model
3740
from time_tracker_api.database import CRUDDao, APICosmosDBDao
@@ -440,18 +443,20 @@ def find_running(self):
440443
# self.stop_time_entry_if_was_left_running(time_entry)
441444
return time_entry
442445

443-
def get_worked_time(self, conditions: dict = {}):
446+
def get_worked_time(self, args: dict = {}):
444447
event_ctx = self.create_event_context(
445448
"read", "Summary of worked time in the current month"
446449
)
447-
conditions.update({"owner_id": event_ctx.user_id})
448450

451+
conditions = {"owner_id": event_ctx.user_id}
449452
time_entries = self.repository.find_all(
450453
event_ctx,
451454
conditions=conditions,
452455
date_range=worked_time.date_range(),
453456
)
454-
return worked_time.summary(time_entries)
457+
return worked_time.summary(
458+
time_entries, time_offset=args.get('time_offset')
459+
)
455460

456461
@staticmethod
457462
def handle_date_filter_args(args: dict) -> dict:

0 commit comments

Comments
 (0)