Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions datasette/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,31 @@ async def allowed(

return result

async def permission_allowed(
self, actor, action, resource=None, *, default=DEFAULT_NOT_SET
):
"""Backward-compatible wrapper around allowed().

Supports the pre-1.0 signature and resource formats:
- None (instance-level)
- "database"
- ("database", "table")

The ``default=`` argument is accepted for compatibility but ignored.
"""
_ = default

if resource is None:
resource_obj = None
elif isinstance(resource, str):
resource_obj = DatabaseResource(database=resource)
elif isinstance(resource, (tuple, list)) and len(resource) == 2:
resource_obj = TableResource(database=resource[0], table=resource[1])
else:
raise TypeError("resource must be None, str, or (database, table) tuple")

return await self.allowed(action=action, resource=resource_obj, actor=actor)

async def ensure_permission(
self,
*,
Expand Down
44 changes: 43 additions & 1 deletion tests/test_internals_datasette.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import dataclasses
from datasette import Context
from datasette.app import Datasette, Database, ResourcesSQL
from datasette.resources import DatabaseResource
from datasette.resources import DatabaseResource, TableResource
from itsdangerous import BadSignature
import pytest

Expand Down Expand Up @@ -206,3 +206,45 @@ async def test_allowed_resources_sql(datasette):
assert isinstance(result, ResourcesSQL)
assert "all_rules AS" in result.sql
assert result.params["action"] == "view-table"


@pytest.mark.asyncio
@pytest.mark.parametrize(
"resource,expected_resource",
(
(None, None),
("fixtures", DatabaseResource(database="fixtures")),
(
("fixtures", "simple_primary_key"),
TableResource("fixtures", "simple_primary_key"),
),
),
)
async def test_permission_allowed_backwards_compatibility(datasette, monkeypatch, resource, expected_resource):
captured = {}

async def fake_allowed(*, action, resource, actor):
captured["action"] = action
captured["resource"] = resource
captured["actor"] = actor
return True

monkeypatch.setattr(datasette, "allowed", fake_allowed)

actor = {"id": "root"}
result = await datasette.permission_allowed(actor=actor, action="view-table", resource=resource)

assert result is True
assert captured["action"] == "view-table"
if expected_resource is None:
assert captured["resource"] is None
else:
assert captured["resource"].parent == expected_resource.parent
assert captured["resource"].child == expected_resource.child
assert captured["actor"] == actor


@pytest.mark.asyncio
async def test_permission_allowed_rejects_invalid_resource(datasette):
with pytest.raises(TypeError):
await datasette.permission_allowed(actor=None, action="view-table", resource=("only-one",))