kopia lustrzana https://github.com/simonw/datasette
Extra permission rules for /-/create, closes #1937
rodzic
e238df3959
commit
c094dde3ff
|
@ -613,6 +613,13 @@ class TableCreateView(BaseView):
|
||||||
ignore = data.get("ignore")
|
ignore = data.get("ignore")
|
||||||
replace = data.get("replace")
|
replace = data.get("replace")
|
||||||
|
|
||||||
|
if replace:
|
||||||
|
# Must have update-row permission
|
||||||
|
if not await self.ds.permission_allowed(
|
||||||
|
request.actor, "update-row", resource=database_name
|
||||||
|
):
|
||||||
|
return _error(["Permission denied - need update-row"], 403)
|
||||||
|
|
||||||
table_name = data.get("table")
|
table_name = data.get("table")
|
||||||
if not table_name:
|
if not table_name:
|
||||||
return _error(["Table is required"])
|
return _error(["Table is required"])
|
||||||
|
@ -630,6 +637,13 @@ class TableCreateView(BaseView):
|
||||||
if rows and row:
|
if rows and row:
|
||||||
return _error(["Cannot specify both rows and row"])
|
return _error(["Cannot specify both rows and row"])
|
||||||
|
|
||||||
|
if rows or row:
|
||||||
|
# Must have insert-row permission
|
||||||
|
if not await self.ds.permission_allowed(
|
||||||
|
request.actor, "insert-row", resource=database_name
|
||||||
|
):
|
||||||
|
return _error(["Permission denied - need insert-row"], 403)
|
||||||
|
|
||||||
if columns:
|
if columns:
|
||||||
if rows or row:
|
if rows or row:
|
||||||
return _error(["Cannot specify columns with rows or row"])
|
return _error(["Cannot specify columns with rows or row"])
|
||||||
|
|
|
@ -830,7 +830,8 @@ If the table is successfully created this will return a ``201`` status code and
|
||||||
Creating a table from example data
|
Creating a table from example data
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Instead of specifying ``columns`` directly you can instead pass a single example ``row`` or a list of ``rows``. Datasette will create a table with a schema that matches those rows and insert them for you:
|
Instead of specifying ``columns`` directly you can instead pass a single example ``row`` or a list of ``rows``.
|
||||||
|
Datasette will create a table with a schema that matches those rows and insert them for you:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
@ -855,6 +856,8 @@ Instead of specifying ``columns`` directly you can instead pass a single example
|
||||||
"pk": "id"
|
"pk": "id"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Doing this requires both the :ref:`permissions_create_table` and :ref:`permissions_insert_row` permissions.
|
||||||
|
|
||||||
The ``201`` response here will be similar to the ``columns`` form, but will also include the number of rows that were inserted as ``row_count``:
|
The ``201`` response here will be similar to the ``columns`` form, but will also include the number of rows that were inserted as ``row_count``:
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
@ -884,6 +887,8 @@ If you pass a row to the create endpoint with a primary key that already exists
|
||||||
|
|
||||||
You can avoid this error by passing the same ``"ignore": true`` or ``"replace": true`` options to the create endpoint as you can to the :ref:`insert endpoint <TableInsertView>`.
|
You can avoid this error by passing the same ``"ignore": true`` or ``"replace": true`` options to the create endpoint as you can to the :ref:`insert endpoint <TableInsertView>`.
|
||||||
|
|
||||||
|
To use the ``"replace": true`` option you will also need the :ref:`permissions_update_row` permission.
|
||||||
|
|
||||||
.. _TableDropView:
|
.. _TableDropView:
|
||||||
|
|
||||||
Dropping tables
|
Dropping tables
|
||||||
|
|
|
@ -1096,6 +1096,50 @@ async def test_create_table(ds_write, input, expected_status, expected_response)
|
||||||
assert data == expected_response
|
assert data == expected_response
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"permissions,body,expected_status,expected_errors",
|
||||||
|
(
|
||||||
|
(["create-table"], {"table": "t", "columns": [{"name": "c"}]}, 201, None),
|
||||||
|
# Need insert-row too if you use "rows":
|
||||||
|
(
|
||||||
|
["create-table"],
|
||||||
|
{"table": "t", "rows": [{"name": "c"}]},
|
||||||
|
403,
|
||||||
|
["Permission denied - need insert-row"],
|
||||||
|
),
|
||||||
|
# This should work:
|
||||||
|
(
|
||||||
|
["create-table", "insert-row"],
|
||||||
|
{"table": "t", "rows": [{"name": "c"}]},
|
||||||
|
201,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
# If you use replace: true you need update-row too:
|
||||||
|
(
|
||||||
|
["create-table", "insert-row"],
|
||||||
|
{"table": "t", "rows": [{"id": 1}], "pk": "id", "replace": True},
|
||||||
|
403,
|
||||||
|
["Permission denied - need update-row"],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def test_create_table_permissions(
|
||||||
|
ds_write, permissions, body, expected_status, expected_errors
|
||||||
|
):
|
||||||
|
token = ds_write.create_token("root", restrict_all=["view-instance"] + permissions)
|
||||||
|
response = await ds_write.client.post(
|
||||||
|
"/data/-/create",
|
||||||
|
json=body,
|
||||||
|
headers=_headers(token),
|
||||||
|
)
|
||||||
|
assert response.status_code == expected_status
|
||||||
|
if expected_errors:
|
||||||
|
data = response.json()
|
||||||
|
assert data["ok"] is False
|
||||||
|
assert data["errors"] == expected_errors
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"input,expected_rows_after",
|
"input,expected_rows_after",
|
||||||
|
|
Ładowanie…
Reference in New Issue