Error for drop against immutable database, closes #1874

This commit is contained in:
Simon Willison 2022-11-13 21:40:10 -08:00
commit 65521f03db
3 changed files with 30 additions and 12 deletions

View file

@ -1236,7 +1236,8 @@ class TableDropView(BaseView):
request.actor, "drop-table", resource=(database_name, table_name) request.actor, "drop-table", resource=(database_name, table_name)
): ):
return _error(["Permission denied"], 403) return _error(["Permission denied"], 403)
if not db.is_mutable:
return _error(["Database is immutable"], 403)
confirm = False confirm = False
try: try:
data = json.loads(await request.post_body()) data = json.loads(await request.post_body())
@ -1248,6 +1249,8 @@ class TableDropView(BaseView):
return Response.json( return Response.json(
{ {
"ok": True, "ok": True,
"database": database_name,
"table": table_name,
"row_count": ( "row_count": (
await db.execute("select count(*) from [{}]".format(table_name)) await db.execute("select count(*) from [{}]".format(table_name))
).single_value(), ).single_value(),

View file

@ -578,6 +578,8 @@ Without a POST body this will return a status ``200`` with a note about how many
{ {
"ok": true, "ok": true,
"database": "<database>",
"table": "<table>",
"row_count": 5, "row_count": 5,
"message": "Pass \"confirm\": true to confirm" "message": "Pass \"confirm\": true to confirm"
} }

View file

@ -8,10 +8,15 @@ import time
def ds_write(tmp_path_factory): def ds_write(tmp_path_factory):
db_directory = tmp_path_factory.mktemp("dbs") db_directory = tmp_path_factory.mktemp("dbs")
db_path = str(db_directory / "data.db") db_path = str(db_directory / "data.db")
db = sqlite3.connect(str(db_path)) db_path_immutable = str(db_directory / "immutable.db")
db.execute("vacuum") db1 = sqlite3.connect(str(db_path))
db.execute("create table docs (id integer primary key, title text, score float)") db2 = sqlite3.connect(str(db_path_immutable))
ds = Datasette([db_path]) for db in (db1, db2):
db.execute("vacuum")
db.execute(
"create table docs (id integer primary key, title text, score float)"
)
ds = Datasette([db_path], immutables=[db_path_immutable])
yield ds yield ds
db.close() db.close()
@ -339,7 +344,9 @@ async def test_delete_row(ds_write, scenario):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize("scenario", ("no_token", "no_perm", "bad_table", "has_perm")) @pytest.mark.parametrize(
"scenario", ("no_token", "no_perm", "bad_table", "has_perm", "immutable")
)
async def test_drop_table(ds_write, scenario): async def test_drop_table(ds_write, scenario):
if scenario == "no_token": if scenario == "no_token":
token = "bad_token" token = "bad_token"
@ -351,7 +358,10 @@ async def test_drop_table(ds_write, scenario):
await ds_write.get_database("data").execute_write( await ds_write.get_database("data").execute_write(
"insert into docs (id, title) values (1, 'Row 1')" "insert into docs (id, title) values (1, 'Row 1')"
) )
path = "/data/{}/-/drop".format("docs" if scenario != "bad_table" else "bad_table") path = "/{database}/{table}/-/drop".format(
database="immutable" if scenario == "immutable" else "data",
table="docs" if scenario != "bad_table" else "bad_table",
)
response = await ds_write.client.post( response = await ds_write.client.post(
path, path,
headers={ headers={
@ -366,17 +376,20 @@ async def test_drop_table(ds_write, scenario):
else 404 else 404
) )
assert response.json()["ok"] is False assert response.json()["ok"] is False
assert ( expected_error = "Permission denied"
response.json()["errors"] == ["Permission denied"] if scenario == "bad_table":
if scenario == "no_token" expected_error = "Table not found: bad_table"
else ["Table not found: bad_table"] elif scenario == "immutable":
) expected_error = "Database is immutable"
assert response.json()["errors"] == [expected_error]
assert (await ds_write.client.get("/data/docs")).status_code == 200 assert (await ds_write.client.get("/data/docs")).status_code == 200
else: else:
# It should show a confirmation page # It should show a confirmation page
assert response.status_code == 200 assert response.status_code == 200
assert response.json() == { assert response.json() == {
"ok": True, "ok": True,
"database": "data",
"table": "docs",
"row_count": 1, "row_count": 1,
"message": 'Pass "confirm": true to confirm', "message": 'Pass "confirm": true to confirm',
} }