Illustrations/web/core/views_user_features.py

112 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# core/views_user_features.py
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse, HttpResponseBadRequest
from django.views.decorators.http import require_POST, require_GET
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from django.forms.models import model_to_dict
from .models import Entry # existing
from .models_user import UserPrefs, SearchHistory, ViewedIllustration
# ---------- Font size prefs ----------
@login_required
@require_POST
def api_set_font_size(request):
size = (request.POST.get("size") or "").lower()
if size not in ("small", "default", "large", "xlarge"):
return JsonResponse({"ok": False, "error": "bad_size"}, status=400)
prefs, _ = UserPrefs.objects.get_or_create(user=request.user)
prefs.font_size = size
prefs.save(update_fields=["font_size"])
return JsonResponse({"ok": True})
@login_required
@require_GET
def api_get_prefs(request):
prefs, _ = UserPrefs.objects.get_or_create(user=request.user)
return JsonResponse({"ok": True, "font_size": prefs.font_size})
# ---------- Search history ----------
# We use Beacon here, so CSRF headers arent available -> mark this one csrf_exempt
@login_required
@csrf_exempt
@require_POST
def api_log_search(request):
q = (request.POST.get("q") or "").strip()
# Expect JSON-like dict from the client for fields, but well accept a flat form too
selected = {}
for k in request.POST:
if k.startswith("sel[") and k.endswith("]"): # sel[subject]=on
name = k[4:-1]
selected[name] = request.POST.get(k) in ("1", "true", "on", "yes")
# consecutive de-duplication
last = SearchHistory.objects.filter(user=request.user).order_by("-created_at").first()
if not last or last.q != q or last.selected != selected:
SearchHistory.objects.create(user=request.user, q=q, selected=selected)
# trim to last 10
ids = list(
SearchHistory.objects.filter(user=request.user)
.order_by("-created_at")
.values_list("id", flat=True)[:10]
)
SearchHistory.objects.filter(user=request.user).exclude(id__in=ids).delete()
return JsonResponse({"ok": True})
@login_required
@require_GET
def api_get_search_history(request):
items = (
SearchHistory.objects.filter(user=request.user)
.order_by("-created_at")
.values("q", "selected", "created_at")
)
# JSON-safe
data = [{"q": i["q"], "selected": i["selected"], "ts": i["created_at"].isoformat()} for i in items]
return JsonResponse({"ok": True, "items": data})
# ---------- Recently viewed ----------
@login_required
@require_POST
def api_log_view(request, entry_id):
try:
e = Entry.objects.get(pk=entry_id)
except Entry.DoesNotExist:
return JsonResponse({"ok": False, "error": "notfound"}, status=404)
ViewedIllustration.objects.create(user=request.user, entry=e)
# trim to 50
ids = list(
ViewedIllustration.objects.filter(user=request.user)
.order_by("-viewed_at")
.values_list("id", flat=True)[:50]
)
ViewedIllustration.objects.filter(user=request.user).exclude(id__in=ids).delete()
return JsonResponse({"ok": True})
@login_required
@require_GET
def api_get_recent_views(request):
rows = (
ViewedIllustration.objects.filter(user=request.user)
.select_related("entry")
.order_by("-viewed_at")[:10] # show 10 (we store 50)
)
data = [
{
"entry_id": r.entry_id,
"viewed_at": r.viewed_at.isoformat(),
"subject": (r.entry.subject or ""),
}
for r in rows
]
return JsonResponse({"ok": True, "items": data})