import json from django.contrib.admin.views.decorators import staff_member_required from django.db.models import Count, Max, Min 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/v263") def login(request): return render(request, "app/login.html") def v1321(request): return redirect("/app/v263") def v1322(request): return redirect("/app/v263") def v133(request): return redirect("/app/v263") def v1332(request): return redirect("/app/v263") def v1333(request): return redirect("/app/v263") def v1334(request): return redirect("/app/v263") def v1335(request): return redirect("/app/v263") def v1340(request): return redirect("/app/v263") def v260(request): return redirect("/app/v263") def v261(request): return redirect("/app/v263") def v262(request): return redirect("/app/v263") def v263(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() # "Nutzer" = Gerät hat PioMint mindestens einmal als installierte PWA # (Standalone) geöffnet - nur das ist echte Nutzung. Ein Gerät, das die # Seite nur im Browser-Tab geöffnet hat, ist ein "Aufrufer", kein Nutzer. user_device_ids = events.filter(is_standalone=True).values_list("device_id", flat=True).distinct() users = events.filter(device_id__in=user_device_ids) visitors_total = events.exclude(device_id__in=user_device_ids).values("device_id").distinct().count() context = { "total_connections": events.count(), "visitors_total": visitors_total, "users_total": user_device_ids.count(), "users_today": users.filter(created_at__gte=today_start).values("device_id").distinct().count(), "users_7d": users.filter(created_at__gte=now - timedelta(days=7)).values("device_id").distinct().count(), "users_30d": users.filter(created_at__gte=now - timedelta(days=30)).values("device_id").distinct().count(), "by_platform": users.values("platform").annotate(count=Count("device_id", distinct=True)).order_by("-count"), "by_browser": users.values("browser").annotate(count=Count("device_id", distinct=True)).order_by("-count"), "device_summary": ( events.values("device_id") .annotate( ping_count=Count("id"), first_seen=Min("created_at"), last_seen=Max("created_at"), standalone_any=Max("is_standalone"), ) .order_by("-last_seen") ), "recent_events": events[:30], } return render(request, "app/dashboard.html", context)