Skip to content

Commit

Permalink
Validates date field ranges are sane (#376)
Browse files Browse the repository at this point in the history
* validates date field ranges are sane

* add extra type checking

* use datetimes only in the tests
  • Loading branch information
Sean Preston authored Apr 27, 2022
1 parent d5851f8 commit 6b44d6c
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 19 deletions.
35 changes: 27 additions & 8 deletions src/fidesops/api/v1/endpoints/privacy_request_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,14 +274,14 @@ def get_request_status(
params: Params = Depends(),
id: Optional[str] = None,
status: Optional[PrivacyRequestStatus] = None,
created_lt: Optional[Union[date, datetime]] = None,
created_gt: Optional[Union[date, datetime]] = None,
started_lt: Optional[Union[date, datetime]] = None,
started_gt: Optional[Union[date, datetime]] = None,
completed_lt: Optional[Union[date, datetime]] = None,
completed_gt: Optional[Union[date, datetime]] = None,
errored_lt: Optional[Union[date, datetime]] = None,
errored_gt: Optional[Union[date, datetime]] = None,
created_lt: Optional[datetime] = None,
created_gt: Optional[datetime] = None,
started_lt: Optional[datetime] = None,
started_gt: Optional[datetime] = None,
completed_lt: Optional[datetime] = None,
completed_gt: Optional[datetime] = None,
errored_lt: Optional[datetime] = None,
errored_gt: Optional[datetime] = None,
external_id: Optional[str] = None,
verbose: Optional[bool] = False,
include_identities: Optional[bool] = False,
Expand All @@ -299,6 +299,25 @@ def get_request_status(
detail="Cannot specify both succeeded and failed query params.",
)

for end, start, field_name in [
[created_lt, created_gt, "created"],
[completed_lt, completed_gt, "completed"],
[errored_lt, errored_gt, "errorer"],
[started_lt, started_gt, "started"],
]:
if end is None or start is None:
continue
if not (isinstance(end, datetime) and isinstance(start, datetime)):
continue
else:
if end < start:
# With date fields, if the start date is after the end date, return a 400
# because no records will lie within this range.
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
detail=f"Value specified for {field_name}_lt: {end} must be after {field_name}_gt: {start}.",
)

query = db.query(PrivacyRequest)

# Further restrict all PrivacyRequests by query params
Expand Down
61 changes: 50 additions & 11 deletions tests/api/v1/endpoints/test_privacy_request_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,8 @@ def test_conflicting_query_params(
):
auth_header = generate_auth_header(scopes=[PRIVACY_REQUEST_READ])
response = api_client.get(
url + f"?completed_lt=2021-01-01&errored_gt=2021-01-02",
url
+ f"?completed_lt=2021-01-01T00:00:00.000Z&errored_gt=2021-01-02T00:00:00.000Z",
headers=auth_header,
)
assert 400 == response.status_code
Expand Down Expand Up @@ -434,14 +435,17 @@ def test_get_privacy_requests_accept_datetime(
mongo_execution_log,
):
auth_header = generate_auth_header(scopes=[PRIVACY_REQUEST_READ])
for date_format in ["%Y-%m-%dT00:00:00.000Z", "%Y-%m-%d"]:
for date_format in [
"%Y-%m-%dT00:00:00.000Z",
# "%Y-%m-%d",
]:
date_input = privacy_request.created_at.strftime(date_format)
response = api_client.get(
url + f"?created_gt={date_input}",
headers=auth_header,
)

assert 200 == response.status_code
assert 200 == response.status_code

def test_get_privacy_requests_by_id(
self,
Expand Down Expand Up @@ -633,19 +637,46 @@ def test_filter_privacy_requests_by_created(
url,
):
auth_header = generate_auth_header(scopes=[PRIVACY_REQUEST_READ])
response = api_client.get(url + f"?created_lt=2019-01-01", headers=auth_header)
response = api_client.get(
url + f"?created_lt=2019-01-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
assert len(resp["items"]) == 0

response = api_client.get(url + f"?created_gt=2019-01-01", headers=auth_header)
response = api_client.get(
url + f"?created_gt=2019-01-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
assert len(resp["items"]) == 3
assert resp["items"][0]["id"] == failed_privacy_request.id
assert resp["items"][1]["id"] == succeeded_privacy_request.id
assert resp["items"][2]["id"] == privacy_request.id

def test_filter_privacy_requests_by_conflicting_date_fields(
self,
api_client: TestClient,
generate_auth_header,
privacy_request,
succeeded_privacy_request,
failed_privacy_request,
url,
):
auth_header = generate_auth_header(scopes=[PRIVACY_REQUEST_READ])
# Search for privacy requests after 2019, but before 2018. This should return an error.
start = "2019-01-01"
end = "2018-01-01"
response = api_client.get(
url + f"?created_gt={start}T00:00:00.000Z&created_lt={end}T00:00:00.000Z",
headers=auth_header,
)
assert 400 == response.status_code
assert (
response.json()["detail"]
== f"Value specified for created_lt: {end} 00:00:00+00:00 must be after created_gt: {start} 00:00:00+00:00."
)

def test_filter_privacy_requests_by_started(
self,
api_client: TestClient,
Expand All @@ -656,14 +687,18 @@ def test_filter_privacy_requests_by_started(
url,
):
auth_header = generate_auth_header(scopes=[PRIVACY_REQUEST_READ])
response = api_client.get(url + f"?started_lt=2021-05-01", headers=auth_header)
response = api_client.get(
url + f"?started_lt=2021-05-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
assert len(resp["items"]) == 2
assert resp["items"][0]["id"] == failed_privacy_request.id
assert resp["items"][1]["id"] == privacy_request.id

response = api_client.get(url + f"?started_gt=2021-05-01", headers=auth_header)
response = api_client.get(
url + f"?started_gt=2021-05-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
assert len(resp["items"]) == 1
Expand All @@ -680,14 +715,14 @@ def test_filter_privacy_requests_by_completed(
):
auth_header = generate_auth_header(scopes=[PRIVACY_REQUEST_READ])
response = api_client.get(
url + f"?completed_lt=2021-10-01", headers=auth_header
url + f"?completed_lt=2021-10-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
assert len(resp["items"]) == 0

response = api_client.get(
url + f"?completed_gt=2021-10-01", headers=auth_header
url + f"?completed_gt=2021-10-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
Expand All @@ -704,12 +739,16 @@ def test_filter_privacy_requests_by_errored(
url,
):
auth_header = generate_auth_header(scopes=[PRIVACY_REQUEST_READ])
response = api_client.get(url + f"?errored_lt=2021-01-01", headers=auth_header)
response = api_client.get(
url + f"?errored_lt=2021-01-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
assert len(resp["items"]) == 0

response = api_client.get(url + f"?errored_gt=2021-01-01", headers=auth_header)
response = api_client.get(
url + f"?errored_gt=2021-01-01T00:00:00.000Z", headers=auth_header
)
assert 200 == response.status_code
resp = response.json()
assert len(resp["items"]) == 1
Expand Down

0 comments on commit 6b44d6c

Please sign in to comment.