kopia lustrzana https://github.com/simonw/datasette
alter: true for row/-/update, refs #2101
rodzic
4e944c29e4
commit
c954795f9a
|
@ -237,11 +237,21 @@ class RowUpdateView(BaseView):
|
||||||
if not "update" in data or not isinstance(data["update"], dict):
|
if not "update" in data or not isinstance(data["update"], dict):
|
||||||
return _error(["JSON must contain an update dictionary"])
|
return _error(["JSON must contain an update dictionary"])
|
||||||
|
|
||||||
|
invalid_keys = set(data.keys()) - {"update", "return", "alter"}
|
||||||
|
if invalid_keys:
|
||||||
|
return _error(["Invalid keys: {}".format(", ".join(invalid_keys))])
|
||||||
|
|
||||||
update = data["update"]
|
update = data["update"]
|
||||||
|
|
||||||
|
alter = data.get("alter")
|
||||||
|
if alter and not await self.ds.permission_allowed(
|
||||||
|
request.actor, "alter-table", resource=(resolved.db.name, resolved.table)
|
||||||
|
):
|
||||||
|
return _error(["Permission denied for alter-table"], 403)
|
||||||
|
|
||||||
def update_row(conn):
|
def update_row(conn):
|
||||||
sqlite_utils.Database(conn)[resolved.table].update(
|
sqlite_utils.Database(conn)[resolved.table].update(
|
||||||
resolved.pk_values, update
|
resolved.pk_values, update, alter=alter
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -787,6 +787,8 @@ The returned JSON will look like this:
|
||||||
|
|
||||||
Any errors will return ``{"errors": ["... descriptive message ..."], "ok": false}``, and a ``400`` status code for a bad input or a ``403`` status code for an authentication or permission error.
|
Any errors will return ``{"errors": ["... descriptive message ..."], "ok": false}``, and a ``400`` status code for a bad input or a ``403`` status code for an authentication or permission error.
|
||||||
|
|
||||||
|
Pass ``"alter: true`` to automatically add any missing columns to the table. This requires the :ref:`permissions_alter_table` permission.
|
||||||
|
|
||||||
.. _RowDeleteView:
|
.. _RowDeleteView:
|
||||||
|
|
||||||
Deleting a row
|
Deleting a row
|
||||||
|
|
|
@ -622,12 +622,17 @@ async def test_delete_row(ds_write, table, row_for_create, pks, delete_path):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("scenario", ("no_token", "no_perm", "bad_table"))
|
@pytest.mark.parametrize(
|
||||||
|
"scenario", ("no_token", "no_perm", "bad_table", "cannot_alter")
|
||||||
|
)
|
||||||
async def test_update_row_check_permission(ds_write, scenario):
|
async def test_update_row_check_permission(ds_write, scenario):
|
||||||
if scenario == "no_token":
|
if scenario == "no_token":
|
||||||
token = "bad_token"
|
token = "bad_token"
|
||||||
elif scenario == "no_perm":
|
elif scenario == "no_perm":
|
||||||
token = write_token(ds_write, actor_id="not-root")
|
token = write_token(ds_write, actor_id="not-root")
|
||||||
|
elif scenario == "cannot_alter":
|
||||||
|
# update-row but no alter-table:
|
||||||
|
token = write_token(ds_write, permissions=["ur"])
|
||||||
else:
|
else:
|
||||||
token = write_token(ds_write)
|
token = write_token(ds_write)
|
||||||
|
|
||||||
|
@ -637,9 +642,13 @@ async def test_update_row_check_permission(ds_write, scenario):
|
||||||
"docs" if scenario != "bad_table" else "bad_table", pk
|
"docs" if scenario != "bad_table" else "bad_table", pk
|
||||||
)
|
)
|
||||||
|
|
||||||
|
json_body = {"update": {"title": "New title"}}
|
||||||
|
if scenario == "cannot_alter":
|
||||||
|
json_body["alter"] = True
|
||||||
|
|
||||||
response = await ds_write.client.post(
|
response = await ds_write.client.post(
|
||||||
path,
|
path,
|
||||||
json={"update": {"title": "New title"}},
|
json=json_body,
|
||||||
headers=_headers(token),
|
headers=_headers(token),
|
||||||
)
|
)
|
||||||
assert response.status_code == 403 if scenario in ("no_token", "bad_token") else 404
|
assert response.status_code == 403 if scenario in ("no_token", "bad_token") else 404
|
||||||
|
@ -651,6 +660,36 @@ async def test_update_row_check_permission(ds_write, scenario):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_update_row_invalid_key(ds_write):
|
||||||
|
token = write_token(ds_write)
|
||||||
|
|
||||||
|
pk = await _insert_row(ds_write)
|
||||||
|
|
||||||
|
path = "/data/docs/{}/-/update".format(pk)
|
||||||
|
response = await ds_write.client.post(
|
||||||
|
path,
|
||||||
|
json={"update": {"title": "New title"}, "bad_key": 1},
|
||||||
|
headers=_headers(token),
|
||||||
|
)
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.json() == {"ok": False, "errors": ["Invalid keys: bad_key"]}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_update_row_alter(ds_write):
|
||||||
|
token = write_token(ds_write, permissions=["ur", "at"])
|
||||||
|
pk = await _insert_row(ds_write)
|
||||||
|
path = "/data/docs/{}/-/update".format(pk)
|
||||||
|
response = await ds_write.client.post(
|
||||||
|
path,
|
||||||
|
json={"update": {"title": "New title", "extra": "extra"}, "alter": True},
|
||||||
|
headers=_headers(token),
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"input,expected_errors",
|
"input,expected_errors",
|
||||||
|
|
Ładowanie…
Reference in New Issue