5.6 KiB
| orphan |
|---|
| true |
Datasette 1.0a20 plugin upgrade guide
Datasette 1.0a20 makes some breaking changes to Datasette's permission system. Plugins need to be updated if they use any of the following:
- The
register_permissions()plugin hook - this should be replaced withregister_actions - The
permission_allowed()plugin hook - this should be upgraded to usepermission_resources_sql(). - The
datasette.permission_allowed()internal method - this should be replaced withdatasette.allowed() - Logic that grants access to the
"root"actor can be removed.
Permissions are now actions
The register_permissions() hook shoud be replaced with register_actions().
Old code:
@hookimpl
def register_permissions(datasette):
return [
Permission(
name="explain-sql",
abbr=None,
description="Can explain SQL queries",
takes_database=True,
takes_resource=False,
default=False,
),
Permission(
name="annotate-rows",
abbr=None,
description="Can annotate rows",
takes_database=True,
takes_resource=True,
default=False,
),
Permission(
name="view-debug-info",
abbr=None,
description="Can view debug information",
takes_database=False,
takes_resource=False,
default=False,
),
]
The new Action does not have a default= parameter.
Here's the equivalent new code:
from datasette import hookimpl
from datasette.permissions import Action
from datasette.resources import DatabaseResource, TableResource
@hookimpl
def register_actions(datasette):
return [
Action(
name="explain-sql",
description="Explain SQL queries",
resource_class=DatabaseResource,
),
Action(
name="annotate-rows",
description="Annotate rows",
resource_class=TableResource,
),
Action(
name="view-debug-info",
description="View debug information",
),
]
The abbr= is now optional and defaults to None.
For actions that apply to specific resources (like databases or tables), specify the resource_class instead of takes_parent and takes_child. Note that view-debug-info does not specify a resource_class because it applies globally.
permission_allowed() hook is replaced by permission_resources_sql()
The following old code:
@hookimpl
def permission_allowed(action):
if action == "permissions-debug":
return True
Can be replaced by:
from datasette.permissions import PermissionSQL
@hookimpl
def permission_resources_sql(action):
return PermissionSQL.allow(reason="datasette-allow-permissions-debug")
A .deny(reason="") class method is also available.
For more complex permission checks consult the documentation for that plugin hook: https://docs.datasette.io/en/latest/plugin_hooks.html#permission-resources-sql-datasette-actor-action
Using datasette.allowed() to check permissions instead of datasette.permission_allowed()
The internal method datasette.permission_allowed() has been replaced by datasette.allowed().
The old method looked like this:
can_debug = await datasette.permission_allowed(
request.actor,
"view-debug-info",
)
can_explain_sql = await datasette.permission_allowed(
request.actor,
"explain-sql",
resource="database_name",
)
can_annotate_rows = await datasette.permission_allowed(
request.actor,
"annotate-rows",
resource=(database_name, table_name),
)
Note the confusing design here where resource could be either a string or a tuple depending on the permission being checked.
The new keyword-only design makes this a lot more clear:
from datasette.resources import DatabaseResource, TableResource
can_debug = await datasette.allowed(
actor=request.actor,
action="view-debug-info",
)
can_explain_sql = await datasette.allowed(
actor=request.actor,
action="explain-sql",
resource=DatabaseResource(database_name),
)
can_annotate_rows = await datasette.allowed(
actor=request.actor,
action="annotate-rows",
resource=TableResource(database_name, table_name),
)
Root user checks are no longer necessary
Some plugins would introduce their own custom permission and then ensure the "root" actor had access to it using a pattern like this:
@hookimpl
def register_permissions(datasette):
return [
Permission(
name="upload-dbs",
abbr=None,
description="Upload SQLite database files",
takes_database=False,
takes_resource=False,
default=False,
)
]
@hookimpl
def permission_allowed(actor, action):
if action == "upload-dbs" and actor and actor.get("id") == "root":
return True
This is no longer necessary in Datasette 1.0a20 - the "root" actor automatically has all permissions when Datasette is started with the datasette --root option.
The permission_allowed() hook in this example can be entirely removed.
Fixing async with httpx.AsyncClient(app=app)
Some older plugins may use the following pattern in their tests, which is no longer supported:
app = Datasette([], memory=True).app()
async with httpx.AsyncClient(app=app) as client:
response = await client.get("http://localhost/path")
The new pattern is to use ds.client like this:
ds = Datasette([], memory=True)
response = await ds.client.get("/path")