diff --git a/web/core/views_user_features.py b/web/core/views_user_features.py index 825fecf..49a14ee 100644 --- a/web/core/views_user_features.py +++ b/web/core/views_user_features.py @@ -33,23 +33,28 @@ def api_get_prefs(request): # ---------- Search history ---------- # We use Beacon here, so CSRF headers aren’t available -> mark this one csrf_exempt @login_required -@csrf_exempt +@csrf_exempt # keep this since you use sendBeacon @require_POST def api_log_search(request): q = (request.POST.get("q") or "").strip() - # Expect JSON-like dict from the client for fields, but we’ll accept a flat form too + + # Collect selected fields from form-style keys: sel[subject]=on selected = {} for k in request.POST: - if k.startswith("sel[") and k.endswith("]"): # sel[subject]=on + if k.startswith("sel[") and k.endswith("]"): name = k[4:-1] selected[name] = request.POST.get(k) in ("1", "true", "on", "yes") - # consecutive de-duplication + # De-dupe consecutive identical searches; if identical, bump timestamp last = SearchHistory.objects.filter(user=request.user).order_by("-created_at").first() - if not last or last.q != q or last.selected != selected: + if last and last.q == q and last.selected == selected: + # bump to "most recent" + last.created_at = timezone.now() + last.save(update_fields=["created_at"]) + else: SearchHistory.objects.create(user=request.user, q=q, selected=selected) - # trim to last 10 + # Trim to last 10 ids = list( SearchHistory.objects.filter(user=request.user) .order_by("-created_at") @@ -61,15 +66,21 @@ def api_log_search(request): @login_required @require_GET +@never_cache def api_get_search_history(request): - items = ( + items_qs = ( 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}) + data = [ + {"q": i["q"], "selected": i["selected"], "ts": i["created_at"].isoformat()} + for i in items_qs + ] + resp = JsonResponse({"ok": True, "items": data}) + resp["Cache-Control"] = "no-store" + return resp + # ---------- Recently viewed ---------- @@ -83,7 +94,7 @@ def api_log_view(request, entry_id): ViewedIllustration.objects.create(user=request.user, entry=e) - # trim to 50 + # Keep only the 50 most recent ids = list( ViewedIllustration.objects.filter(user=request.user) .order_by("-viewed_at") @@ -95,18 +106,31 @@ def api_log_view(request, entry_id): @login_required @require_GET +@never_cache 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) + .order_by("-viewed_at")[:10] ) + + def first_words(text, n=20): + import re as _re + clean = _re.sub(r"\s+", " ", (text or "")).strip() + if not clean: + return "" + words = clean.split(" ") + return clean if len(words) <= n else " ".join(words[:n]) + "…" + data = [ { "entry_id": r.entry_id, "viewed_at": r.viewed_at.isoformat(), - "subject": (r.entry.subject or ""), + "illustration": r.entry.illustration or "", # <-- what the UI expects + "snippet": first_words(r.entry.illustration or "", 20), } for r in rows ] - return JsonResponse({"ok": True, "items": data}) \ No newline at end of file + resp = JsonResponse({"ok": True, "items": data}) + resp["Cache-Control"] = "no-store" + return resp \ No newline at end of file