mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Better display of recent permissions checks, refs #2543
This commit is contained in:
parent
b018eb3171
commit
5da3c9f4bd
2 changed files with 65 additions and 56 deletions
|
|
@ -134,31 +134,33 @@ debugPost.addEventListener('submit', function(ev) {
|
||||||
{% if filter != "only-yours" %}<a href="?filter=only-yours">Only yours</a>{% else %}<strong>Only yours</strong>{% endif %}
|
{% if filter != "only-yours" %}<a href="?filter=only-yours">Only yours</a>{% else %}<strong>Only yours</strong>{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% for check in permission_checks %}
|
{% if permission_checks %}
|
||||||
<div class="check">
|
<table class="rows-and-columns permission-checks-table" id="permission-checks-table">
|
||||||
<h2>
|
<thead>
|
||||||
<span class="check-action">{{ check.action }}</span>
|
<tr>
|
||||||
checked at
|
<th>When</th>
|
||||||
<span class="check-when">{{ check.when }}</span>
|
<th>Action</th>
|
||||||
{% if check.result %}
|
<th>Parent</th>
|
||||||
<span class="check-result check-result-true">✓</span>
|
<th>Child</th>
|
||||||
{% elif check.result is none %}
|
<th>Actor</th>
|
||||||
<span class="check-result check-result-no-opinion">none</span>
|
<th>Result</th>
|
||||||
{% else %}
|
</tr>
|
||||||
<span class="check-result check-result-false">✗</span>
|
</thead>
|
||||||
{% endif %}
|
<tbody>
|
||||||
</h2>
|
{% for check in permission_checks %}
|
||||||
<p><strong>Actor:</strong> {{ check.actor|tojson }}</p>
|
<tr>
|
||||||
{% if check.parent %}
|
<td><span style="font-size: 0.8em">{{ check.when.split('T', 1)[0] }}</span><br>{{ check.when.split('T', 1)[1].split('+', 1)[0].split('-', 1)[0].split('Z', 1)[0] }}</td>
|
||||||
<p><strong>Resource:</strong>
|
<td><code>{{ check.action }}</code></td>
|
||||||
{% if check.child %}
|
<td>{{ check.parent or '—' }}</td>
|
||||||
{{ check.parent }} / {{ check.child }}
|
<td>{{ check.child or '—' }}</td>
|
||||||
{% else %}
|
<td>{% if check.actor %}<code>{{ check.actor|tojson }}</code>{% else %}<span class="check-actor-anon">anonymous</span>{% endif %}</td>
|
||||||
{{ check.parent }}
|
<td>{% if check.result %}<span class="check-result check-result-true">Allowed</span>{% elif check.result is none %}<span class="check-result check-result-no-opinion">No opinion</span>{% else %}<span class="check-result check-result-false">Denied</span>{% endif %}</td>
|
||||||
{% endif %}
|
</tr>
|
||||||
</p>
|
{% endfor %}
|
||||||
{% endif %}
|
</tbody>
|
||||||
</div>
|
</table>
|
||||||
{% endfor %}
|
{% else %}
|
||||||
|
<p class="no-results">No permission checks have been recorded yet.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -398,24 +398,27 @@ async def test_permissions_debug(ds_client, filter_):
|
||||||
assert fragment in response.text
|
assert fragment in response.text
|
||||||
# Should show one failure and one success
|
# Should show one failure and one success
|
||||||
soup = Soup(response.text, "html.parser")
|
soup = Soup(response.text, "html.parser")
|
||||||
check_divs = soup.find_all("div", {"class": "check"})
|
table = soup.find("table", {"id": "permission-checks-table"})
|
||||||
checks = [
|
rows = table.find("tbody").find_all("tr")
|
||||||
{
|
checks = []
|
||||||
"action": div.select_one(".check-action").text,
|
for row in rows:
|
||||||
# True = green tick, False = red cross, None = gray None
|
cells = row.find_all("td")
|
||||||
"result": (
|
result_cell = cells[5]
|
||||||
None
|
if result_cell.select_one(".check-result-true"):
|
||||||
if div.select(".check-result-no-opinion")
|
result = True
|
||||||
else bool(div.select(".check-result-true"))
|
elif result_cell.select_one(".check-result-false"):
|
||||||
),
|
result = False
|
||||||
"actor": json.loads(
|
else:
|
||||||
div.find(
|
result = None
|
||||||
"strong", string=lambda text: text and "Actor" in text
|
actor_code = cells[4].find("code")
|
||||||
).parent.text.split(": ", 1)[1]
|
actor = json.loads(actor_code.text) if actor_code else None
|
||||||
),
|
checks.append(
|
||||||
}
|
{
|
||||||
for div in check_divs
|
"action": cells[1].text.strip(),
|
||||||
]
|
"result": result,
|
||||||
|
"actor": actor,
|
||||||
|
}
|
||||||
|
)
|
||||||
expected_checks = [
|
expected_checks = [
|
||||||
{
|
{
|
||||||
"action": "permissions-debug",
|
"action": "permissions-debug",
|
||||||
|
|
@ -723,22 +726,26 @@ async def test_actor_restricted_permissions(
|
||||||
},
|
},
|
||||||
cookies=cookies,
|
cookies=cookies,
|
||||||
)
|
)
|
||||||
# Build expected_resource to match API behavior:
|
# Response mirrors /-/check JSON structure
|
||||||
# - None when no resources
|
if resource_1 is None:
|
||||||
# - Single string when only resource_1
|
expected_path = "/"
|
||||||
# - List when both resource_1 and resource_2 (JSON serializes tuples as lists)
|
elif resource_2 is None:
|
||||||
if resource_1 and resource_2:
|
expected_path = f"/{resource_1}"
|
||||||
expected_resource = [resource_1, resource_2]
|
|
||||||
elif resource_1:
|
|
||||||
expected_resource = resource_1
|
|
||||||
else:
|
else:
|
||||||
expected_resource = None
|
expected_path = f"/{resource_1}/{resource_2}"
|
||||||
expected = {
|
|
||||||
"actor": actor,
|
expected_resource = {
|
||||||
"permission": permission,
|
"parent": resource_1,
|
||||||
"resource": expected_resource,
|
"child": resource_2,
|
||||||
"result": expected_result,
|
"path": expected_path,
|
||||||
}
|
}
|
||||||
|
expected = {
|
||||||
|
"action": permission,
|
||||||
|
"allowed": expected_result,
|
||||||
|
"resource": expected_resource,
|
||||||
|
}
|
||||||
|
if actor.get("id"):
|
||||||
|
expected["actor_id"] = actor["id"]
|
||||||
assert response.json() == expected
|
assert response.json() == expected
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue