mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Refactor breadcrumbs to respect permissions, refs #1831
This commit is contained in:
parent
b7fec7f902
commit
1a5e5f2aa9
13 changed files with 65 additions and 59 deletions
|
|
@ -631,6 +631,44 @@ class Datasette:
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
async def _crumb_items(self, request, table=None, database=None):
|
||||||
|
crumbs = []
|
||||||
|
# Top-level link
|
||||||
|
if await self.permission_allowed(
|
||||||
|
actor=request.actor, action="view-instance", default=True
|
||||||
|
):
|
||||||
|
crumbs.append({"href": self.urls.instance(), "label": "home"})
|
||||||
|
# Database link
|
||||||
|
if database:
|
||||||
|
if await self.permission_allowed(
|
||||||
|
actor=request.actor,
|
||||||
|
action="view-database",
|
||||||
|
resource=database,
|
||||||
|
default=True,
|
||||||
|
):
|
||||||
|
crumbs.append(
|
||||||
|
{
|
||||||
|
"href": self.urls.database(database),
|
||||||
|
"label": database,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# Table link
|
||||||
|
if table:
|
||||||
|
assert database, "table= requires database="
|
||||||
|
if await self.permission_allowed(
|
||||||
|
actor=request.actor,
|
||||||
|
action="view-table",
|
||||||
|
resource=(database, table),
|
||||||
|
default=True,
|
||||||
|
):
|
||||||
|
crumbs.append(
|
||||||
|
{
|
||||||
|
"href": self.urls.table(database, table),
|
||||||
|
"label": table,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return crumbs
|
||||||
|
|
||||||
async def permission_allowed(self, actor, action, resource=None, default=False):
|
async def permission_allowed(self, actor, action, resource=None, default=False):
|
||||||
"""Check permissions using the permissions_allowed plugin hook"""
|
"""Check permissions using the permissions_allowed plugin hook"""
|
||||||
result = None
|
result = None
|
||||||
|
|
@ -1009,6 +1047,8 @@ class Datasette:
|
||||||
template_context = {
|
template_context = {
|
||||||
**context,
|
**context,
|
||||||
**{
|
**{
|
||||||
|
"request": request,
|
||||||
|
"crumb_items": self._crumb_items,
|
||||||
"urls": self.urls,
|
"urls": self.urls,
|
||||||
"actor": request.actor if request else None,
|
"actor": request.actor if request else None,
|
||||||
"menu_links": menu_links,
|
"menu_links": menu_links,
|
||||||
|
|
|
||||||
15
datasette/templates/_crumbs.html
Normal file
15
datasette/templates/_crumbs.html
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% macro nav(request, database=None, table=None) -%}
|
||||||
|
{% if crumb_items is defined %}
|
||||||
|
{% set items=crumb_items(request=request, database=database, table=table) %}
|
||||||
|
{% if items %}
|
||||||
|
<p class="crumbs">
|
||||||
|
{% for item in items %}
|
||||||
|
<a href="{{ item.href }}">{{ item.label }}</a>
|
||||||
|
{% if not loop.last %}
|
||||||
|
/
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
{% import "_crumbs.html" as crumbs with context %}<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body class="{% block body_class %}{% endblock %}">
|
<body class="{% block body_class %}{% endblock %}">
|
||||||
<div class="not-footer">
|
<div class="not-footer">
|
||||||
<header><nav>{% block nav %}
|
<header><nav>{% block nav %}{% block crumbs %}{{ crumbs.nav(request=request) }}{% endblock %}
|
||||||
{% set links = menu_links() %}{% if links or show_logout %}
|
{% set links = menu_links() %}{% if links or show_logout %}
|
||||||
<details class="nav-menu">
|
<details class="nav-menu">
|
||||||
<summary><svg aria-labelledby="nav-menu-svg-title" role="img"
|
<summary><svg aria-labelledby="nav-menu-svg-title" role="img"
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,7 @@
|
||||||
|
|
||||||
{% block body_class %}db db-{{ database|to_css_class }}{% endblock %}
|
{% block body_class %}db db-{{ database|to_css_class }}{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
|
||||||
<p class="crumbs">
|
|
||||||
<a href="{{ urls.instance() }}">home</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
<div class="page-header" style="border-color: #{{ database_color(database) }}">
|
<div class="page-header" style="border-color: #{{ database_color(database) }}">
|
||||||
<h1>{{ metadata.title or database }}{% if private %} 🔒{% endif %}</h1>
|
<h1>{{ metadata.title or database }}{% if private %} 🔒{% endif %}</h1>
|
||||||
{% set links = database_actions() %}{% if links %}
|
{% set links = database_actions() %}{% if links %}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,6 @@
|
||||||
|
|
||||||
{% block title %}{% if title %}{{ title }}{% else %}Error {{ status }}{% endif %}{% endblock %}
|
{% block title %}{% if title %}{{ title }}{% else %}Error {{ status }}{% endif %}{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
|
||||||
<p class="crumbs">
|
|
||||||
<a href="{{ urls.instance() }}">home</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<h1>{% if title %}{{ title }}{% else %}Error {{ status }}{% endif %}</h1>
|
<h1>{% if title %}{{ title }}{% else %}Error {{ status }}{% endif %}</h1>
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,6 @@
|
||||||
|
|
||||||
{% block title %}Log out{% endblock %}
|
{% block title %}Log out{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
|
||||||
<p class="crumbs">
|
|
||||||
<a href="{{ base_url }}">home</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<h1>Log out</h1>
|
<h1>Log out</h1>
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,6 @@
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
|
||||||
<p class="crumbs">
|
|
||||||
<a href="{{ base_url }}">home</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<h1>Recent permissions checks</h1>
|
<h1>Recent permissions checks</h1>
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,8 @@
|
||||||
|
|
||||||
{% block body_class %}query db-{{ database|to_css_class }}{% if canned_query %} query-{{ canned_query|to_css_class }}{% endif %}{% endblock %}
|
{% block body_class %}query db-{{ database|to_css_class }}{% if canned_query %} query-{{ canned_query|to_css_class }}{% endif %}{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
{% block crumbs %}
|
||||||
<p class="crumbs">
|
{{ crumbs.nav(request=request, database=database) }}
|
||||||
<a href="{{ urls.instance() }}">home</a> /
|
|
||||||
<a href="{{ urls.database(database) }}">{{ database }}</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,8 @@
|
||||||
|
|
||||||
{% block body_class %}row db-{{ database|to_css_class }} table-{{ table|to_css_class }}{% endblock %}
|
{% block body_class %}row db-{{ database|to_css_class }} table-{{ table|to_css_class }}{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
{% block crumbs %}
|
||||||
<p class="crumbs">
|
{{ crumbs.nav(request=request, database=database, table=table) }}
|
||||||
<a href="{{ urls.instance() }}">home</a> /
|
|
||||||
<a href="{{ urls.database(database) }}">{{ database }}</a> /
|
|
||||||
<a href="{{ urls.table(database, table) }}">{{ table }}</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,6 @@
|
||||||
|
|
||||||
{% block body_class %}show-json{% endblock %}
|
{% block body_class %}show-json{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
|
||||||
<p class="crumbs">
|
|
||||||
<a href="{{ urls.instance() }}">home</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ filename }}</h1>
|
<h1>{{ filename }}</h1>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,8 @@
|
||||||
|
|
||||||
{% block body_class %}table db-{{ database|to_css_class }} table-{{ table|to_css_class }}{% endblock %}
|
{% block body_class %}table db-{{ database|to_css_class }} table-{{ table|to_css_class }}{% endblock %}
|
||||||
|
|
||||||
{% block nav %}
|
{% block crumbs %}
|
||||||
<p class="crumbs">
|
{{ crumbs.nav(request=request, database=database) }}
|
||||||
<a href="{{ urls.instance() }}">home</a> /
|
|
||||||
<a href="{{ urls.database(database) }}">{{ database }}</a>
|
|
||||||
</p>
|
|
||||||
{{ super() }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,7 @@ def test_permissions_debug(app_client):
|
||||||
{"action": "permissions-debug", "result": True, "used_default": False},
|
{"action": "permissions-debug", "result": True, "used_default": False},
|
||||||
{"action": "view-instance", "result": None, "used_default": True},
|
{"action": "view-instance", "result": None, "used_default": True},
|
||||||
{"action": "debug-menu", "result": False, "used_default": True},
|
{"action": "debug-menu", "result": False, "used_default": True},
|
||||||
|
{"action": "view-instance", "result": True, "used_default": True},
|
||||||
{"action": "permissions-debug", "result": False, "used_default": True},
|
{"action": "permissions-debug", "result": False, "used_default": True},
|
||||||
{"action": "view-instance", "result": None, "used_default": True},
|
{"action": "view-instance", "result": None, "used_default": True},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -845,7 +845,7 @@ def test_hook_menu_links(app_client):
|
||||||
def get_menu_links(html):
|
def get_menu_links(html):
|
||||||
soup = Soup(html, "html.parser")
|
soup = Soup(html, "html.parser")
|
||||||
return [
|
return [
|
||||||
{"label": a.text, "href": a["href"]} for a in soup.find("nav").select("a")
|
{"label": a.text, "href": a["href"]} for a in soup.select(".nav-menu a")
|
||||||
]
|
]
|
||||||
|
|
||||||
response = app_client.get("/")
|
response = app_client.get("/")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue