mirror of
https://github.com/simonw/datasette.git
synced 2026-06-04 08:07:01 +02:00
parent
4b5fac9cf7
commit
040e42ddca
11 changed files with 182 additions and 99 deletions
|
|
@ -17,13 +17,6 @@ UNION/INTERSECT operations. The order of evaluation is:
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from datasette.app import Datasette
|
||||
|
||||
from datasette import hookimpl
|
||||
|
||||
# Re-export all hooks and public utilities
|
||||
from .restrictions import (
|
||||
actor_restrictions_sql as actor_restrictions_sql,
|
||||
|
|
@ -38,12 +31,3 @@ from .defaults import (
|
|||
default_query_permissions_sql as default_query_permissions_sql,
|
||||
DEFAULT_ALLOW_ACTIONS as DEFAULT_ALLOW_ACTIONS,
|
||||
)
|
||||
|
||||
|
||||
@hookimpl
|
||||
def canned_queries(datasette: "Datasette", database: str, actor) -> dict:
|
||||
"""Return canned queries defined in datasette.yaml configuration."""
|
||||
queries = (
|
||||
((datasette.config or {}).get("databases") or {}).get(database) or {}
|
||||
).get("queries") or {}
|
||||
return queries
|
||||
|
|
|
|||
|
|
@ -74,6 +74,22 @@ async def default_query_permissions_sql(
|
|||
actor: Optional[dict],
|
||||
action: str,
|
||||
) -> Optional[PermissionSQL]:
|
||||
actor_id = actor.get("id") if isinstance(actor, dict) else None
|
||||
|
||||
if action in {"update-query", "delete-query"}:
|
||||
if actor_id is None:
|
||||
return None
|
||||
return PermissionSQL(
|
||||
sql="""
|
||||
SELECT database_name AS parent, name AS child, 1 AS allow,
|
||||
'query owner' AS reason
|
||||
FROM queries
|
||||
WHERE source = 'user'
|
||||
AND owner_id = :query_owner_id
|
||||
""",
|
||||
params={"query_owner_id": actor_id},
|
||||
)
|
||||
|
||||
if action != "view-query":
|
||||
return None
|
||||
|
||||
|
|
@ -98,6 +114,19 @@ async def default_query_permissions_sql(
|
|||
AND source IN ('config', 'plugin')
|
||||
"""
|
||||
|
||||
user_writable_sql = ""
|
||||
if actor_id is not None:
|
||||
params["query_owner_id"] = actor_id
|
||||
user_writable_sql = """
|
||||
UNION ALL
|
||||
SELECT database_name AS parent, name AS child, 1 AS allow,
|
||||
'query owner' AS reason
|
||||
FROM queries
|
||||
WHERE is_write = 1
|
||||
AND source = 'user'
|
||||
AND owner_id = :query_owner_id
|
||||
"""
|
||||
|
||||
return PermissionSQL(
|
||||
sql=f"""
|
||||
WITH execute_sql_allowed AS (
|
||||
|
|
@ -118,6 +147,7 @@ async def default_query_permissions_sql(
|
|||
WHERE q.is_write = 0
|
||||
AND q.published = 0
|
||||
{trusted_writable_sql}
|
||||
{user_writable_sql}
|
||||
""",
|
||||
params=params,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -137,11 +137,6 @@ def permission_resources_sql(datasette, actor, action):
|
|||
"""
|
||||
|
||||
|
||||
@hookspec
|
||||
def canned_queries(datasette, database, actor):
|
||||
"""Return a dictionary of canned query definitions or an awaitable function that returns them"""
|
||||
|
||||
|
||||
@hookspec
|
||||
def register_magic_parameters(datasette):
|
||||
"""Return a list of (name, function) magic parameter functions"""
|
||||
|
|
|
|||
|
|
@ -945,6 +945,18 @@ class QueryView(View):
|
|||
# That should not have happened
|
||||
raise DatasetteError("Unexpected table found on POST", status=404)
|
||||
|
||||
if not await datasette.allowed(
|
||||
action="view-query",
|
||||
resource=QueryResource(database=db.name, query=canned_query["name"]),
|
||||
actor=request.actor,
|
||||
):
|
||||
raise Forbidden("You do not have permission to view this query")
|
||||
|
||||
if canned_query.get("write") and canned_query.get("source") == "user":
|
||||
await datasette.ensure_query_write_permissions(
|
||||
db.name, canned_query["sql"], actor=request.actor
|
||||
)
|
||||
|
||||
# If database is immutable, return an error
|
||||
if not db.is_mutable:
|
||||
raise Forbidden("Database is immutable")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue