mirror of
https://github.com/simonw/datasette.git
synced 2026-09-11 19:14:07 +02:00
Filter foreign-key helper targets by view permission
This commit is contained in:
parent
bf348a22fc
commit
c01e95f3bd
2 changed files with 44 additions and 3 deletions
|
|
@ -27,6 +27,11 @@ from datasette.utils import (
|
|||
table_column_details,
|
||||
)
|
||||
from datasette.utils.asgi import NotFound, PayloadTooLarge, Response
|
||||
from datasette.utils.permissions import (
|
||||
SKIP_PERMISSION_CHECKS,
|
||||
gather_permission_sql_from_hooks,
|
||||
resolve_permissions_with_candidates,
|
||||
)
|
||||
from datasette.utils.sqlite import sqlite_hidden_table_names
|
||||
|
||||
from .base import BaseView
|
||||
|
|
@ -122,6 +127,30 @@ def _public_foreign_key_target(target):
|
|||
}
|
||||
|
||||
|
||||
async def _filter_visible_foreign_key_targets(datasette, actor, database_name, targets):
|
||||
if not targets:
|
||||
return []
|
||||
|
||||
permission_sqls = await gather_permission_sql_from_hooks(
|
||||
datasette=datasette,
|
||||
actor=actor,
|
||||
action="view-table",
|
||||
)
|
||||
if permission_sqls is SKIP_PERMISSION_CHECKS:
|
||||
return targets
|
||||
|
||||
candidate_tables = list(dict.fromkeys(target["fk_table"] for target in targets))
|
||||
permission_rows = await resolve_permissions_with_candidates(
|
||||
datasette.get_internal_database(),
|
||||
actor,
|
||||
permission_sqls,
|
||||
[(database_name, table_name) for table_name in candidate_tables],
|
||||
"view-table",
|
||||
)
|
||||
visible_tables = {row["child"] for row in permission_rows if bool(row["allow"])}
|
||||
return [target for target in targets if target["fk_table"] in visible_tables]
|
||||
|
||||
|
||||
def _singular(name):
|
||||
if name.endswith("ies") and len(name) > 3:
|
||||
return name[:-3] + "y"
|
||||
|
|
@ -1014,6 +1043,9 @@ class DatabaseForeignKeyTargetsView(BaseView):
|
|||
for target in (await db.execute(FOREIGN_KEY_TARGETS_SQL)).dicts()
|
||||
if target["fk_table"] not in hidden_tables
|
||||
]
|
||||
targets = await _filter_visible_foreign_key_targets(
|
||||
self.ds, request.actor, database_name, targets
|
||||
)
|
||||
return Response.json(
|
||||
{
|
||||
"ok": True,
|
||||
|
|
@ -1052,6 +1084,15 @@ class TableForeignKeySuggestionsView(BaseView):
|
|||
source_columns, targets, current_by_column = await db.execute_fn(
|
||||
lambda conn: _foreign_key_suggestion_metadata(conn, table_name)
|
||||
)
|
||||
targets = await _filter_visible_foreign_key_targets(
|
||||
self.ds, request.actor, database_name, targets
|
||||
)
|
||||
visible_target_tables = {target["fk_table"] for target in targets}
|
||||
current_by_column = {
|
||||
column: current
|
||||
for column, current in current_by_column.items()
|
||||
if current["fk_table"] in visible_target_tables
|
||||
}
|
||||
|
||||
columns = []
|
||||
options_by_column = {}
|
||||
|
|
|
|||
|
|
@ -1296,7 +1296,7 @@ async def test_alter_table_foreign_key_without_fk_column_requires_single_pk(ds_w
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_foreign_key_suggestions(ds_write):
|
||||
token = write_token(ds_write, permissions=["at"])
|
||||
token = write_token(ds_write, permissions=["alter-table", "view-table"])
|
||||
db = ds_write.get_database("data")
|
||||
await db.execute_write("create table owners (id integer primary key)")
|
||||
await db.execute_write("insert into owners (id) values (1), (2), (3)")
|
||||
|
|
@ -1362,7 +1362,7 @@ async def test_foreign_key_suggestions_permission_denied(ds_write):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_foreign_key_suggestions_fail_open(ds_write, monkeypatch):
|
||||
token = write_token(ds_write, permissions=["at"])
|
||||
token = write_token(ds_write, permissions=["alter-table", "view-table"])
|
||||
db = ds_write.get_database("data")
|
||||
await db.execute_write("create table owners (id integer primary key)")
|
||||
|
||||
|
|
@ -1393,7 +1393,7 @@ async def test_foreign_key_suggestions_fail_open(ds_write, monkeypatch):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_foreign_key_targets(ds_write):
|
||||
token = write_token(ds_write, permissions=["ct"])
|
||||
token = write_token(ds_write, permissions=["create-table", "view-table"])
|
||||
db = ds_write.get_database("data")
|
||||
await db.execute_write("create table owners (id integer primary key)")
|
||||
await db.execute_write("create table categories (slug varchar(30) primary key)")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue