forked from reactive-python/reactpy-django
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathviews.py
64 lines (50 loc) · 2.45 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import asyncio
import os
from urllib.parse import parse_qs
from django.core.cache import caches
from django.core.exceptions import SuspiciousOperation
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
from reactpy.config import REACTPY_WEB_MODULES_DIR
from reactpy_django.utils import create_cache_key, render_view
async def web_modules_file(request: HttpRequest, file: str) -> HttpResponse:
"""Gets JavaScript required for ReactPy modules at runtime. These modules are
returned from cache if available."""
from reactpy_django.config import REACTPY_CACHE
web_modules_dir = REACTPY_WEB_MODULES_DIR.current
path = os.path.abspath(web_modules_dir.joinpath(file))
# Prevent attempts to walk outside of the web modules dir
if str(web_modules_dir) != os.path.commonpath((path, web_modules_dir)):
raise SuspiciousOperation(
"Attempt to access a directory outside of REACTPY_WEB_MODULES_DIR."
)
# Fetch the file from cache, if available
last_modified_time = os.stat(path).st_mtime
cache_key = create_cache_key("web_modules", path)
file_contents = await caches[REACTPY_CACHE].aget(
cache_key, version=int(last_modified_time)
)
if file_contents is None:
with open(path, "r", encoding="utf-8") as fp:
file_contents = await asyncio.to_thread(fp.read)
await caches[REACTPY_CACHE].adelete(cache_key)
await caches[REACTPY_CACHE].aset(
cache_key, file_contents, timeout=604800, version=int(last_modified_time)
)
# TODO: Convert this to a StreamingHttpResponse
return HttpResponse(file_contents, content_type="text/javascript")
async def view_to_iframe(request: HttpRequest, dotted_path: str) -> HttpResponse:
"""Returns a view that was registered by reactpy_django.components.view_to_iframe."""
from reactpy_django.config import REACTPY_REGISTERED_IFRAME_VIEWS
# Get the view
registered_view = REACTPY_REGISTERED_IFRAME_VIEWS.get(dotted_path)
if not registered_view:
return HttpResponseNotFound()
# Get args and kwargs from the request
query = request.META.get("QUERY_STRING", "")
kwargs = {k: v if len(v) > 1 else v[0] for k, v in parse_qs(query).items()}
args = kwargs.pop("_args", [])
# Render the view
response = await render_view(registered_view, request, args, kwargs)
# Ensure page can be rendered as an iframe
response["X-Frame-Options"] = "SAMEORIGIN"
return response