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
41 changes: 35 additions & 6 deletions src/sentry/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,36 @@

MIN_STATS_PERIOD = timedelta(hours=1)
MAX_STATS_PERIOD = timedelta(days=90)
# make sure to update this message if you are changing the min/max period
INVALID_PERIOD_ERROR = 'Time window must be greater than an hour and less than or equal to 90 days'


class InvalidParams(Exception):
pass


def get_datetime_from_stats_period(stats_period, now=None):
if now is None:
now = timezone.now()
stats_period = parse_stats_period(stats_period)
if stats_period is None:
raise InvalidParams('Invalid statsPeriod')
return now - stats_period


def get_date_range_from_params(params, optional=False):
"""
Gets a date range from standard date range params we pass to the api.

If `statsPeriod` is passed then convert to a time delta and make sure it
fits within our min/max period length. Values are in the format
<number><period_type>, where period type is one of `s` (seconds),
`m` (minutes), `h` (hours) or `d` (days).

Similarly, `statsPeriodStart` and `statsPeriodEnd` allow for selecting a
relative range, for example: 15 days ago through 8 days ago. This uses the same
format as `statsPeriod`

:param params:
If `start` end `end` are passed, validate them, convert to `datetime` and
returns them if valid.
Expand All @@ -35,11 +52,18 @@ def get_date_range_from_params(params, optional=False):
start = now - MAX_STATS_PERIOD

stats_period = params.get('statsPeriod')
stats_period_start = params.get('statsPeriodStart')
stats_period_end = params.get('statsPeriodEnd')

if stats_period is not None:
stats_period = parse_stats_period(stats_period)
if stats_period is None or stats_period < MIN_STATS_PERIOD or stats_period >= MAX_STATS_PERIOD:
raise InvalidParams('Invalid statsPeriod')
start = now - stats_period
start = get_datetime_from_stats_period(stats_period, now)

elif stats_period_start or stats_period_end:
if not all([stats_period_start, stats_period_end]):
raise InvalidParams('statsPeriodStart and statsPeriodEnd are both required')
start = get_datetime_from_stats_period(stats_period_start, now)
end = get_datetime_from_stats_period(stats_period_end, now)

elif params.get('start') or params.get('end'):
if not all([params.get('start'), params.get('end')]):
raise InvalidParams('start and end are both required')
Expand All @@ -48,9 +72,14 @@ def get_date_range_from_params(params, optional=False):
end = parse_datetime_string(params['end'])
except InvalidQuery as exc:
raise InvalidParams(exc.message)
if start > end:
raise InvalidParams('start must be before end')
elif optional:
return None, None

if start > end:
raise InvalidParams('start must be before end')

delta = end - start
if delta < MIN_STATS_PERIOD or delta > MAX_STATS_PERIOD:
raise InvalidParams(INVALID_PERIOD_ERROR)

return start, end
18 changes: 18 additions & 0 deletions tests/sentry/api/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,21 @@ def test_no_params(self):
start, end = get_date_range_from_params({}, optional=True)
assert start is None
assert end is None

@freeze_time('2018-12-11 03:21:34')
def test_relative_date_range(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be worth testing having statsPeriod(Start|End) missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

start, end = get_date_range_from_params({
'statsPeriodStart': '14d',
'statsPeriodEnd': '7d',
})

assert start == datetime.datetime(2018, 11, 27, 3, 21, 34, tzinfo=timezone.utc)
assert end == datetime.datetime(2018, 12, 4, 3, 21, 34, tzinfo=timezone.utc)

@freeze_time('2018-12-11 03:21:34')
def test_relative_date_range_incomplete(self):

with self.assertRaises(InvalidParams):
start, end = get_date_range_from_params({
'statsPeriodStart': '14d',
})