mirror of
https://github.com/simonw/datasette.git
synced 2026-05-27 12:34:37 +02:00
Tweak URL designs of new endpoints
This commit is contained in:
parent
8ab8999ba9
commit
f1dd86ebfb
9 changed files with 25 additions and 25 deletions
|
|
@ -2745,11 +2745,11 @@ class Datasette:
|
|||
)
|
||||
add_route(
|
||||
QueryInsertView.as_view(self),
|
||||
r"/(?P<database>[^\/\.]+)/-/queries/-/insert$",
|
||||
r"/(?P<database>[^\/\.]+)/-/queries/insert$",
|
||||
)
|
||||
add_route(
|
||||
ExecuteWriteAnalyzeView.as_view(self),
|
||||
r"/(?P<database>[^\/\.]+)/-/execute-write/-/analyze$",
|
||||
r"/(?P<database>[^\/\.]+)/-/execute-write/analyze$",
|
||||
)
|
||||
add_route(
|
||||
ExecuteWriteView.as_view(self),
|
||||
|
|
@ -2761,7 +2761,7 @@ class Datasette:
|
|||
)
|
||||
add_route(
|
||||
QueryParametersView.as_view(self),
|
||||
r"/(?P<database>[^\/\.]+)/-/query/-/parameters$",
|
||||
r"/(?P<database>[^\/\.]+)/-/query/parameters$",
|
||||
)
|
||||
add_route(
|
||||
wrap_view(QueryView, self),
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
||||
|
||||
{% if allow_execute_sql %}
|
||||
<form class="sql core" action="{{ urls.database(database) }}/-/query" method="get" data-parameters-url="{{ urls.database(database) }}/-/query/-/parameters">
|
||||
<form class="sql core" action="{{ urls.database(database) }}/-/query" method="get" data-parameters-url="{{ urls.database(database) }}/-/query/parameters">
|
||||
<h3>Custom SQL query</h3>
|
||||
<p class="sql-editor"><textarea id="sql-editor" name="sql">{% if tables %}select * from {{ tables[0].name|escape_sqlite }}{% else %}select sqlite_version(){% endif %}</textarea></p>
|
||||
{% set parameter_names = [] %}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
<p class="{% if execution_ok %}message-info{% else %}message-error{% endif %}">{{ execution_message }}{% for link in execution_links %} <a href="{{ link.href }}">{{ link.label }}</a>{% endfor %}</p>
|
||||
{% endif %}
|
||||
|
||||
<form class="sql core" action="{{ urls.database(database) }}/-/execute-write" method="post" data-analyze-url="{{ urls.database(database) }}/-/execute-write/-/analyze">
|
||||
<form class="sql core" action="{{ urls.database(database) }}/-/execute-write" method="post" data-analyze-url="{{ urls.database(database) }}/-/execute-write/analyze">
|
||||
{% if write_template_tables %}
|
||||
<div class="execute-write-template-menu">
|
||||
<details>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
||||
|
||||
<form class="sql core" action="{{ urls.database(database) }}{% if canned_query %}/{{ canned_query }}{% endif %}" method="{% if canned_query_write %}post{% else %}get{% endif %}" data-parameters-url="{{ urls.database(database) }}/-/query/-/parameters">
|
||||
<form class="sql core" action="{{ urls.database(database) }}{% if canned_query %}/{{ canned_query }}{% endif %}" method="{% if canned_query_write %}post{% else %}get{% endif %}" data-parameters-url="{{ urls.database(database) }}/-/query/parameters">
|
||||
<h3>Custom SQL query{% if display_rows %} returning {% if truncated %}more than {% endif %}{{ "{:,}".format(display_rows|length) }} row{% if display_rows|length == 1 %}{% else %}s{% endif %}{% endif %}{% if not query_error %}
|
||||
<span class="show-hide-sql">(<a href="{{ show_hide_link }}">{{ show_hide_text }}</a>)</span>
|
||||
{% endif %}</h3>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<h1 style="padding-left: 10px; border-left: 10px solid #{{ database_color }}">Create query</h1>
|
||||
|
||||
<form class="sql core" action="{{ urls.database(database) }}/-/queries/-/insert" method="post">
|
||||
<form class="sql core" action="{{ urls.database(database) }}/-/queries/insert" method="post">
|
||||
<p><label for="query-name">Name</label> <input id="query-name" name="name" type="text"></p>
|
||||
<p><label for="query-title">Title</label> <input id="query-title" name="title" type="text"></p>
|
||||
<p><label for="query-description">Description</label><br><textarea id="query-description" name="description" rows="3"></textarea></p>
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ Creating saved queries in the UI
|
|||
Creating saved queries
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``POST /<database>/-/queries/-/insert`` creates a saved query. This requires ``execute-sql`` and ``insert-query`` for the database.
|
||||
``POST /<database>/-/queries/insert`` creates a saved query. This requires ``execute-sql`` and ``insert-query`` for the database.
|
||||
|
||||
.. _QueryParametersView:
|
||||
.. _ExecuteWriteView:
|
||||
|
|
@ -534,13 +534,13 @@ Creating saved queries
|
|||
Executing write SQL
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``GET /<database>/-/query/-/parameters?sql=...`` returns the named parameters used by a SQL query. This requires ``execute-sql`` for the database.
|
||||
``GET /<database>/-/query/parameters?sql=...`` returns the named parameters used by a SQL query. This requires ``execute-sql`` for the database.
|
||||
|
||||
``GET /<database>/-/execute-write`` displays a form for executing writable SQL. A ``?sql=`` query string pre-populates the form without executing it.
|
||||
|
||||
``POST /<database>/-/execute-write`` executes writable SQL. This requires ``execute-write-sql`` for the database plus the relevant table-level write permissions.
|
||||
|
||||
``GET /<database>/-/execute-write/-/analyze?sql=...`` returns the derived parameters plus the write operations that SQL would need in order to execute.
|
||||
``GET /<database>/-/execute-write/analyze?sql=...`` returns the derived parameters plus the write operations that SQL would need in order to execute.
|
||||
|
||||
.. _QueryDefinitionView:
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ JSON endpoints should follow Datasette's existing write API style: use `POST` pl
|
|||
Endpoints:
|
||||
|
||||
- `GET /-/queries` and `GET /{database}/-/queries` show searchable HTML query browsers. `GET /-/queries.json` lists query definitions across every database the actor can view; `GET /{database}/-/queries.json` scopes that list to one database. Both JSON endpoints use cursor pagination with `_next` and `_size`.
|
||||
- `POST /{database}/-/queries/-/insert` creates a query.
|
||||
- `POST /{database}/-/queries/insert` creates a query.
|
||||
- `GET /{database}/{query}/-/definition` returns one query definition without executing it.
|
||||
- `POST /{database}/{query}/-/update` updates one query.
|
||||
- `POST /{database}/{query}/-/delete` deletes one query.
|
||||
|
|
@ -388,7 +388,7 @@ The read methods should reconstruct the existing dictionary shape used by query
|
|||
|
||||
On `/{database}/-/query`, if the actor has both `execute-sql` and `insert-query`, show a save control for valid read-only SQL. That page already executes read-only arbitrary SQL, so the first UI can stay read-only even though the JSON API can accept writable SQL after `Database.analyze_sql()` validation.
|
||||
|
||||
The save form should call `POST /{database}/-/queries/-/insert` and default to `is_published=false`.
|
||||
The save form should call `POST /{database}/-/queries/insert` and default to `is_published=false`.
|
||||
|
||||
If the actor also has `publish-query`, include a publish control. The UI copy should make it clear that publishing allows people without arbitrary SQL permission to run this query.
|
||||
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ async def test_query_parameter_form_fields(ds_client):
|
|||
'<label for="qp1">name</label> <input type="text" id="qp1" name="name" value="" data-parameter-control>'
|
||||
in response.text
|
||||
)
|
||||
assert 'data-parameters-url="/fixtures/-/query/-/parameters"' in response.text
|
||||
assert 'data-parameters-url="/fixtures/-/query/parameters"' in response.text
|
||||
assert 'id="sql-parameters-section"' in response.text
|
||||
assert "setupSqlParameterRefresh" in response.text
|
||||
response2 = await ds_client.get("/fixtures/-/query?sql=select+:name&name=hello")
|
||||
|
|
@ -344,7 +344,7 @@ async def test_query_parameter_form_fields(ds_client):
|
|||
async def test_database_page_sql_parameter_refresh_markup(ds_client):
|
||||
response = await ds_client.get("/fixtures")
|
||||
assert response.status_code == 200
|
||||
assert 'data-parameters-url="/fixtures/-/query/-/parameters"' in response.text
|
||||
assert 'data-parameters-url="/fixtures/-/query/parameters"' in response.text
|
||||
assert 'id="sql-parameters-section"' in response.text
|
||||
assert "setupSqlParameterRefresh" in response.text
|
||||
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ async def test_query_insert_api_creates_read_only_query():
|
|||
await ds.invoke_startup()
|
||||
|
||||
response = await ds.client.post(
|
||||
"/data/-/queries/-/insert",
|
||||
"/data/-/queries/insert",
|
||||
actor={"id": "root"},
|
||||
json={
|
||||
"query": {
|
||||
|
|
@ -568,7 +568,7 @@ async def test_query_insert_api_publish_requires_publish_query():
|
|||
await ds.invoke_startup()
|
||||
|
||||
response = await ds.client.post(
|
||||
"/data/-/queries/-/insert",
|
||||
"/data/-/queries/insert",
|
||||
actor={"id": "writer"},
|
||||
json={"query": {"name": "public", "sql": "select 1", "is_published": True}},
|
||||
)
|
||||
|
|
@ -586,7 +586,7 @@ async def test_query_insert_api_creates_writable_query():
|
|||
await ds.invoke_startup()
|
||||
|
||||
response = await ds.client.post(
|
||||
"/data/-/queries/-/insert",
|
||||
"/data/-/queries/insert",
|
||||
actor={"id": "root"},
|
||||
json={
|
||||
"query": {
|
||||
|
|
@ -603,7 +603,7 @@ async def test_query_insert_api_creates_writable_query():
|
|||
assert query["parameters"] == ["name"]
|
||||
|
||||
bad_response = await ds.client.post(
|
||||
"/data/-/queries/-/insert",
|
||||
"/data/-/queries/insert",
|
||||
actor={"id": "root"},
|
||||
json={
|
||||
"query": {
|
||||
|
|
@ -671,7 +671,7 @@ async def test_query_insert_api_rejects_magic_parameters():
|
|||
await ds.invoke_startup()
|
||||
|
||||
response = await ds.client.post(
|
||||
"/data/-/queries/-/insert",
|
||||
"/data/-/queries/insert",
|
||||
actor={"id": "root"},
|
||||
json={"query": {"name": "magic", "sql": "select :_actor_id"}},
|
||||
)
|
||||
|
|
@ -742,7 +742,7 @@ async def test_execute_write_get_prepopulates_without_executing():
|
|||
assert 'data-sql-template="insert"' in response.text
|
||||
assert 'data-sql-template="update"' in response.text
|
||||
assert 'data-sql-template="delete"' in response.text
|
||||
assert 'data-analyze-url="/data/-/execute-write/-/analyze"' in response.text
|
||||
assert 'data-analyze-url="/data/-/execute-write/analyze"' in response.text
|
||||
assert 'addEventListener("paste"' in response.text
|
||||
assert "setupSqlParameterRefresh" in response.text
|
||||
assert '<table class="execute-write-analysis">' in response.text
|
||||
|
|
@ -771,12 +771,12 @@ async def test_execute_write_analyze_endpoint_uses_sql_only():
|
|||
await ds.invoke_startup()
|
||||
|
||||
response = await ds.client.get(
|
||||
"/data/-/execute-write/-/analyze",
|
||||
"/data/-/execute-write/analyze",
|
||||
actor={"id": "root"},
|
||||
params={"sql": "insert into dogs (name) values (:name)"},
|
||||
)
|
||||
read_only_response = await ds.client.get(
|
||||
"/data/-/execute-write/-/analyze",
|
||||
"/data/-/execute-write/analyze",
|
||||
actor={"id": "root"},
|
||||
params={"sql": "select * from dogs where name = :name"},
|
||||
)
|
||||
|
|
@ -818,19 +818,19 @@ async def test_query_parameters_endpoint_uses_get_sql_only():
|
|||
await ds.invoke_startup()
|
||||
|
||||
response = await ds.client.get(
|
||||
"/data/-/query/-/parameters",
|
||||
"/data/-/query/parameters",
|
||||
actor={"id": "root"},
|
||||
params={
|
||||
"sql": "select * from dogs where name = :name and id = :id",
|
||||
},
|
||||
)
|
||||
permission_denied_response = await ds.client.get(
|
||||
"/data/-/query/-/parameters",
|
||||
"/data/-/query/parameters",
|
||||
actor={"id": "not-root"},
|
||||
params={"sql": "select * from dogs where name = :name"},
|
||||
)
|
||||
magic_parameter_response = await ds.client.get(
|
||||
"/data/-/query/-/parameters",
|
||||
"/data/-/query/parameters",
|
||||
actor={"id": "root"},
|
||||
params={"sql": "select :_actor_id"},
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue