Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
128 changes: 108 additions & 20 deletions tests/time_tracker_api/time_entries/time_entries_namespace_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
get_current_month,
current_datetime,
current_datetime_str,
get_date_range_of_month,
datetime_str,
)
from utils import worked_time

Expand Down Expand Up @@ -581,35 +583,121 @@ def test_create_with_valid_uuid_format_should_return_created(


@pytest.mark.parametrize(
'url,month,year',
'url',
[
('/time-entries?month=4&year=2020', 4, 2020),
('/time-entries?month=4', 4, get_current_year()),
('/time-entries', get_current_month(), get_current_year()),
(
'/time-entries?start_date=2020-04-01T00:00:00&end_date=2020-04-30T23:00:00'
),
('/time-entries?month=4&year=2020'),
('/time-entries?month=4'),
('/time-entries?year=2020'),
('/time-entries'),
],
)
def test_find_all_is_called_with_generated_dates(
def test_get_all_passes_date_range_built_from_params_to_find_all(
client: FlaskClient, valid_header: dict, url: str, time_entries_dao
):
time_entries_dao.repository.find_all = Mock(return_value=[])

response = client.get(url, headers=valid_header)

time_entries_dao.repository.find_all.assert_called_once()
_, kwargs = time_entries_dao.repository.find_all.call_args
assert 'date_range' in kwargs
assert 'start_date' in kwargs['date_range']
assert 'end_date' in kwargs['date_range']


@pytest.mark.parametrize(
'url,start_date,end_date',
[
(
'/time-entries?month=4&year=2020',
'2020-04-01T05:00:00+00:00',
'2020-05-01T04:59:59.999999+00:00',
),
(
'/time-entries?start_date=2020-04-01T00:00:00&end_date=2020-04-30T23:00:00',
'2020-04-01T05:00:00+00:00',
'2020-05-01T04:00:00+00:00',
),
],
)
def test_get_all_passes_date_range_to_find_all_with_default_tz_offset(
client: FlaskClient,
mocker: MockFixture,
valid_header: dict,
owner_id: str,
time_entries_dao,
url: str,
month: int,
year: int,
start_date: str,
end_date: str,
):
from time_tracker_api.time_entries.time_entries_namespace import (
time_entries_dao,
)
time_entries_dao.repository.find_all = Mock(return_value=[])

dao_get_all_mock = mocker.patch.object(
time_entries_dao, 'get_all', return_value=[]
)
response = client.get(url, headers=valid_header)

response = client.get(url, headers=valid_header, follow_redirects=True)
time_entries_dao.repository.find_all.assert_called_once()
_, kwargs = time_entries_dao.repository.find_all.call_args
assert 'date_range' in kwargs
assert 'start_date' in kwargs['date_range']
assert 'end_date' in kwargs['date_range']
assert kwargs['date_range']['start_date'] == start_date
assert kwargs['date_range']['end_date'] == end_date

assert HTTPStatus.OK == response.status_code
assert json.loads(response.data) is not None
dao_get_all_mock.assert_called_once()

@pytest.mark.parametrize(
'url,start_date,end_date',
[
(
'/time-entries?month=4&year=2020&timezone_offset=300',
'2020-04-01T05:00:00+00:00',
'2020-05-01T04:59:59.999999+00:00',
),
(
'/time-entries?start_date=2020-04-01T00:00:00&end_date=2020-04-30T23:00:00&timezone_offset=300',
'2020-04-01T05:00:00+00:00',
'2020-05-01T04:00:00+00:00',
),
(
'/time-entries?month=4&year=2020&timezone_offset=-120',
'2020-03-31T22:00:00+00:00',
'2020-04-30T21:59:59.999999+00:00',
),
(
'/time-entries?start_date=2020-04-01T00:00:00&end_date=2020-04-30T23:00:00&timezone_offset=-120',
'2020-03-31T22:00:00+00:00',
'2020-04-30T21:00:00+00:00',
),
(
'/time-entries?month=4&year=2020&timezone_offset=420',
'2020-04-01T07:00:00+00:00',
'2020-05-01T06:59:59.999999+00:00',
),
(
'/time-entries?start_date=2020-04-01T00:00:00&end_date=2020-04-30T23:00:00&timezone_offset=420',
'2020-04-01T07:00:00+00:00',
'2020-05-01T06:00:00+00:00',
),
],
)
def test_get_all_passes_date_range_to_find_all_with_given_tz_offset(
client: FlaskClient,
valid_header: dict,
time_entries_dao,
url: str,
start_date: str,
end_date: str,
):
time_entries_dao.repository.find_all = Mock(return_value=[])

response = client.get(url, headers=valid_header)

time_entries_dao.repository.find_all.assert_called_once()
_, kwargs = time_entries_dao.repository.find_all.call_args
assert 'date_range' in kwargs
assert 'start_date' in kwargs['date_range']
assert 'end_date' in kwargs['date_range']
assert kwargs['date_range']['start_date'] == start_date
assert kwargs['date_range']['end_date'] == end_date


def test_summary_is_called_with_date_range_from_worked_time_module(
Expand Down Expand Up @@ -678,6 +766,6 @@ def test_paginated_sends_max_count_and_offset_on_call_to_repository(

time_entries_dao.repository.find_all.assert_called_once()

args, kwargs = time_entries_dao.repository.find_all.call_args
_, kwargs = time_entries_dao.repository.find_all.call_args
assert 'max_count' in kwargs and kwargs['max_count'] is not None
assert 'offset' in kwargs and kwargs['offset'] is not None
40 changes: 16 additions & 24 deletions time_tracker_api/time_entries/time_entries_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from flask_restplus import abort
from flask_restplus._http import HTTPStatus

from datetime import datetime, timedelta
from datetime import timedelta

from commons.data_access_layer.cosmos_db import (
CosmosDBDao,
Expand Down Expand Up @@ -556,30 +556,22 @@ def get_worked_time(self, args: dict):

@staticmethod
def handle_date_filter_args(args: dict) -> dict:
date_range = None
year = None
month = None
if 'month' and 'year' in args:
month = int(args.get("month"))
year = int(args.get("year"))
args.pop('month')
args.pop('year')
elif "start_date" and "end_date" in args:
date_range = args.copy()
if "owner_id" in date_range:
date_range.pop("owner_id")
args.pop("start_date")
args.pop("end_date")
elif 'month' in args:
month = int(args.get("month"))
year = get_current_year()
args.pop('month')
if "start_date" and "end_date" in args:
start_date = str_to_datetime(args.pop('start_date'))
end_date = str_to_datetime(args.pop('end_date'))
else:
month = get_current_month()
year = get_current_year()
return (
date_range if date_range else get_date_range_of_month(year, month)
)
month = int(args.pop("month", get_current_month()))
year = int(args.pop("year", get_current_year()))
start_date, end_date = get_date_range_of_month(year, month)

offset_in_minutes = int(args.pop('timezone_offset', 300))
start_date = start_date + timedelta(minutes=offset_in_minutes)
end_date = end_date + timedelta(minutes=offset_in_minutes)

return {
'start_date': datetime_str(start_date),
'end_date': datetime_str(end_date),
}


def create_dao() -> TimeEntriesDao:
Expand Down
8 changes: 8 additions & 0 deletions time_tracker_api/time_entries/time_entries_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@
location='args',
)

attributes_filter.add_argument(
'timezone_offset',
required=False,
store_missing=False,
help="(Filter) Time zone difference, in minutes, from current locale (host system settings) to UTC.",
location='args',
)


@ns.route('')
class TimeEntries(Resource):
Expand Down
15 changes: 4 additions & 11 deletions utils/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,26 @@ def get_current_day() -> int:
return datetime.now(pytz.UTC).day


def get_date_range_of_month(year: int, month: int) -> Dict[str, str]:
def get_date_range_of_month(year: int, month: int):
def get_last_day_of_month(year: int, month: int) -> int:
from calendar import monthrange

return monthrange(year=year, month=month)[1]

first_day_of_month = 1
start_date = datetime(
year=year, month=month, day=first_day_of_month, tzinfo=timezone.utc
)
start_date = datetime(year=year, month=month, day=1, tzinfo=timezone.utc)

last_day_of_month = get_last_day_of_month(year=year, month=month)
end_date = datetime(
year=year,
month=month,
day=last_day_of_month,
day=get_last_day_of_month(year, month),
hour=23,
minute=59,
second=59,
microsecond=999999,
tzinfo=timezone.utc,
)

return {
'start_date': datetime_str(start_date),
'end_date': datetime_str(end_date),
}
return start_date, end_date


def str_to_datetime(value: str) -> datetime:
Expand Down