You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piomint/app/views.py

112 lines
3.6 KiB

import json
from django.contrib.admin.views.decorators import staff_member_required
from django.db.models import Count
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse, redirect
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from datetime import timedelta
from .models import UsageEvent
from .utils import parse_user_agent
# Create your views here.
def index(request):
return render(request, "app/base.html")
def install(request):
return render(request, "app/install.html")
def home(request):
return redirect("/app/v261")
def login(request):
return render(request, "app/login.html")
def v1321(request):
return redirect("/app/v261")
def v1322(request):
return redirect("/app/v261")
def v133(request):
return redirect("/app/v261")
def v1332(request):
return redirect("/app/v261")
def v1333(request):
return redirect("/app/v261")
def v1334(request):
return redirect("/app/v261")
def v1335(request):
return redirect("/app/v261")
def v1340(request):
return redirect("/app/v261")
def v260(request):
return redirect("/app/v261")
def v261(request):
return render(request, "app/home.html")
# ---------------------------------------------------------------------------
# Anonyme Nutzungsstatistik fürs Admin-Dashboard
# ---------------------------------------------------------------------------
@csrf_exempt
@require_POST
def track_usage(request):
"""Nimmt ein anonymes Nutzungssignal entgegen (ein Aufruf pro Gerät und Tag,
siehe home01.js: pingUsageIfNeeded()). Kein CSRF-Schutz nötig, da rein additiv
und ohne jeden Personenbezug - device_id kommt aus dem localStorage des Geräts."""
try:
data = json.loads(request.body or "{}")
except json.JSONDecodeError:
data = {}
device_id = str(data.get("device_id", "")).strip()[:64]
if not device_id:
return JsonResponse({"ok": False, "error": "device_id fehlt"}, status=400)
user_agent = request.META.get("HTTP_USER_AGENT", "")
platform, browser = parse_user_agent(user_agent)
UsageEvent.objects.create(
device_id=device_id,
app_version=str(data.get("app_version", ""))[:20],
user_agent=user_agent[:1000],
platform=platform,
browser=browser,
is_standalone=bool(data.get("standalone", False)),
)
return JsonResponse({"ok": True})
@staff_member_required
def usage_dashboard(request):
"""Nutzungs-Dashboard für Admins - nur für angemeldete Staff-Nutzer (Django-Admin-Login)."""
now = timezone.now()
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
events = UsageEvent.objects.all()
context = {
"unique_devices_total": events.values("device_id").distinct().count(),
"devices_today": events.filter(created_at__gte=today_start).values("device_id").distinct().count(),
"devices_7d": events.filter(created_at__gte=now - timedelta(days=7)).values("device_id").distinct().count(),
"devices_30d": events.filter(created_at__gte=now - timedelta(days=30)).values("device_id").distinct().count(),
"standalone_count": events.filter(is_standalone=True).values("device_id").distinct().count(),
"by_platform": events.values("platform").annotate(count=Count("device_id", distinct=True)).order_by("-count"),
"by_browser": events.values("browser").annotate(count=Count("device_id", distinct=True)).order_by("-count"),
"recent_events": events[:30],
}
return render(request, "app/dashboard.html", context)

Powered by TurnKey Linux.