From f84acae98ed99c3045d6a00e04cc72984cfa68dd Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Tue, 13 Dec 2022 14:23:07 -0800 Subject: [PATCH] Return 400 errors for ?_sort errors, closes #1950 --- datasette/views/table.py | 8 +++++--- tests/test_table_html.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/datasette/views/table.py b/datasette/views/table.py index 3fd4b9aa..ecf6f15b 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -387,17 +387,19 @@ class TableView(DataView): sort_desc = table_metadata.get("sort_desc") if sort and sort_desc: - raise DatasetteError("Cannot use _sort and _sort_desc at the same time") + raise DatasetteError( + "Cannot use _sort and _sort_desc at the same time", status=400 + ) if sort: if sort not in sortable_columns: - raise DatasetteError(f"Cannot sort table by {sort}") + raise DatasetteError(f"Cannot sort table by {sort}", status=400) order_by = escape_sqlite(sort) if sort_desc: if sort_desc not in sortable_columns: - raise DatasetteError(f"Cannot sort table by {sort_desc}") + raise DatasetteError(f"Cannot sort table by {sort_desc}", status=400) order_by = f"{escape_sqlite(sort_desc)} desc" diff --git a/tests/test_table_html.py b/tests/test_table_html.py index 5ffbda8f..f8e7c295 100644 --- a/tests/test_table_html.py +++ b/tests/test_table_html.py @@ -891,6 +891,36 @@ def test_custom_table_include(): ) == str(Soup(response.text, "html.parser").select_one("div.custom-table-row")) +@pytest.mark.parametrize("json", (True, False)) +@pytest.mark.parametrize( + "params,error", + ( + ("?_sort=bad", "Cannot sort table by bad"), + ("?_sort_desc=bad", "Cannot sort table by bad"), + ( + "?_sort=state&_sort_desc=state", + "Cannot use _sort and _sort_desc at the same time", + ), + ), +) +def test_sort_errors(app_client, json, params, error): + path = "/fixtures/facetable{}{}".format( + ".json" if json else "", + params, + ) + response = app_client.get(path) + assert response.status == 400 + if json: + assert response.json == { + "ok": False, + "error": error, + "status": 400, + "title": None, + } + else: + assert error in response.text + + def test_metadata_sort(app_client): response = app_client.get("/fixtures/facet_cities") assert response.status == 200