datasette/datasette/views/special.py

166 wiersze
5.4 KiB
Python

import json
from datasette.utils.asgi import Response, Forbidden
from datasette.utils import actor_matches_allow, add_cors_headers
from .base import BaseView
import secrets
class JsonDataView(BaseView):
name = "json_data"
def __init__(self, datasette, filename, data_callback, needs_request=False):
self.ds = datasette
self.filename = filename
self.data_callback = data_callback
self.needs_request = needs_request
async def get(self, request):
as_format = request.url_vars["as_format"]
await self.check_permission(request, "view-instance")
if self.needs_request:
data = self.data_callback(request)
else:
data = self.data_callback()
if as_format:
headers = {}
if self.ds.cors:
add_cors_headers(headers)
return Response(
json.dumps(data),
content_type="application/json; charset=utf-8",
headers=headers,
)
else:
return await self.render(
["show_json.html"],
request=request,
context={
"filename": self.filename,
"data_json": json.dumps(data, indent=4),
},
)
class PatternPortfolioView(BaseView):
name = "patterns"
has_json_alternate = False
async def get(self, request):
await self.check_permission(request, "view-instance")
return await self.render(["patterns.html"], request=request)
class AuthTokenView(BaseView):
name = "auth_token"
has_json_alternate = False
async def get(self, request):
token = request.args.get("token") or ""
if not self.ds._root_token:
raise Forbidden("Root token has already been used")
if secrets.compare_digest(token, self.ds._root_token):
self.ds._root_token = None
response = Response.redirect(self.ds.urls.instance())
response.set_cookie(
"ds_actor", self.ds.sign({"a": {"id": "root"}}, "actor")
)
return response
else:
raise Forbidden("Invalid token")
class LogoutView(BaseView):
name = "logout"
has_json_alternate = False
async def get(self, request):
if not request.actor:
return Response.redirect(self.ds.urls.instance())
return await self.render(
["logout.html"],
request,
{"actor": request.actor},
)
async def post(self, request):
response = Response.redirect(self.ds.urls.instance())
response.set_cookie("ds_actor", "", expires=0, max_age=0)
self.ds.add_message(request, "You are now logged out", self.ds.WARNING)
return response
class PermissionsDebugView(BaseView):
name = "permissions_debug"
has_json_alternate = False
async def get(self, request):
await self.check_permission(request, "view-instance")
if not await self.ds.permission_allowed(request.actor, "permissions-debug"):
raise Forbidden("Permission denied")
return await self.render(
["permissions_debug.html"],
request,
# list() avoids error if check is performed during template render:
{"permission_checks": list(reversed(self.ds._permission_checks))},
)
class AllowDebugView(BaseView):
name = "allow_debug"
has_json_alternate = False
async def get(self, request):
errors = []
actor_input = request.args.get("actor") or '{"id": "root"}'
try:
actor = json.loads(actor_input)
actor_input = json.dumps(actor, indent=4)
except json.decoder.JSONDecodeError as ex:
errors.append(f"Actor JSON error: {ex}")
allow_input = request.args.get("allow") or '{"id": "*"}'
try:
allow = json.loads(allow_input)
allow_input = json.dumps(allow, indent=4)
except json.decoder.JSONDecodeError as ex:
errors.append(f"Allow JSON error: {ex}")
result = None
if not errors:
result = str(actor_matches_allow(actor, allow))
return await self.render(
["allow_debug.html"],
request,
{
"result": result,
"error": "\n\n".join(errors) if errors else "",
"actor_input": actor_input,
"allow_input": allow_input,
},
)
class MessagesDebugView(BaseView):
name = "messages_debug"
has_json_alternate = False
async def get(self, request):
await self.check_permission(request, "view-instance")
return await self.render(["messages_debug.html"], request)
async def post(self, request):
await self.check_permission(request, "view-instance")
post = await request.post_vars()
message = post.get("message", "")
message_type = post.get("message_type") or "INFO"
assert message_type in ("INFO", "WARNING", "ERROR", "all")
datasette = self.ds
if message_type == "all":
datasette.add_message(request, message, datasette.INFO)
datasette.add_message(request, message, datasette.WARNING)
datasette.add_message(request, message, datasette.ERROR)
else:
datasette.add_message(request, message, getattr(datasette, message_type))
return Response.redirect(self.ds.urls.instance())