55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
from django.conf import settings
|
|
from django.contrib.admin.views.decorators import staff_member_required
|
|
from django.contrib.staticfiles import finders
|
|
from django.http import FileResponse, Http404
|
|
from django.middleware.csrf import get_token
|
|
from django.shortcuts import render
|
|
|
|
from tracker.models import ScheduledDose
|
|
|
|
|
|
def service_worker(request):
|
|
"""The built worker (frontend/src/sw.ts), from the root so its scope covers /admin/.
|
|
|
|
Served by a view rather than the staticfiles machinery because the URL must
|
|
stay stable and unhashed — a renamed worker would be a brand-new worker.
|
|
"""
|
|
path = finders.find("sw.js")
|
|
if path is None:
|
|
raise Http404("Frontend not built yet — run: make frontend")
|
|
|
|
response = FileResponse(open(path, "rb"), content_type="application/javascript")
|
|
# Browsers cap service-worker caching anyway; make updates immediate.
|
|
response["Cache-Control"] = "no-cache"
|
|
return response
|
|
|
|
|
|
@staff_member_required
|
|
def app(request):
|
|
"""The single-page app shell: Vue routes between Today and Recap client-side.
|
|
|
|
All data flows through the API; the shell only carries the per-page-load
|
|
facts the frontend cannot fetch (CSRF token) or that feed the reminder
|
|
diagnostics.
|
|
"""
|
|
active_doses = ScheduledDose.objects.filter(
|
|
is_active=True, medication__is_active=True
|
|
)
|
|
|
|
return render(
|
|
request,
|
|
"tracker/app.html",
|
|
{
|
|
"config": {
|
|
"vapidPublicKey": settings.VAPID_PUBLIC_KEY,
|
|
# get_token also sets the CSRF cookie for the session.
|
|
"csrfToken": get_token(request),
|
|
"activeDoses": active_doses.count(),
|
|
"dosesWithReminders": active_doses.filter(
|
|
reminder_time__isnull=False
|
|
).count(),
|
|
"subscribedDevices": request.user.push_subscriptions.count(),
|
|
}
|
|
},
|
|
)
|