From 99434e29f5bf7407aa3a9aa6711e07507eccbe38 Mon Sep 17 00:00:00 2001 From: Joshua Laymon Date: Sun, 7 Sep 2025 18:39:57 +0000 Subject: [PATCH] Update web/core/views.py --- web/core/views.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/web/core/views.py b/web/core/views.py index a2b7f57..a2a478c 100644 --- a/web/core/views.py +++ b/web/core/views.py @@ -25,6 +25,7 @@ from django.contrib.staticfiles.storage import staticfiles_storage from django.db import transaction from . import utils as core_utils from .models_audit import AuditLog +from .scripture_normalizer import normalize_scripture_field # Order + labels used in the Search UI @@ -118,6 +119,9 @@ def search_page(request): - quoted phrases - * and ? wildcards (regex); if regex returns zero, falls back to icontains - AND across tokens, OR across the selected fields + + Special power term: + - 'invalidscripture' -> returns only entries whose scripture would trigger red pills (validation warnings) """ default_fields = { "subject": True, @@ -143,6 +147,56 @@ def search_page(request): q = (request.GET.get("q") or "").strip() if q: + # ✨ Special command: list entries whose Scripture validation would fail (red pills) + if q.lower() == "invalidscripture": + qs = Entry.objects.exclude(scripture_raw="").only("id", "scripture_raw", "date_added") + invalid_ids = [] + # Reuse the same rules your front-end uses + for e in qs.iterator(chunk_size=1000): + _norm, warnings = normalize_scripture_field((e.scripture_raw or "").strip()) + if warnings: + invalid_ids.append(e.id) + + # Keep your standard sort order (newest first, then id desc) + ids = list( + Entry.objects.filter(id__in=invalid_ids) + .order_by("-date_added", "-id") + .values_list("id", flat=True) + ) + + try: + print(f"[search] q='invalidscripture' count={len(ids)}") + except Exception: + pass + + request.session["result_ids"] = ids + request.session["last_search"] = {"q": q, "fields": ["scripture_raw"]} + request.session.modified = True + + count = len(ids) + if count: + entry = Entry.objects.get(pk=ids[0]) + ctx = entry_context(entry, ids) + ctx.update({"from_search": True}) + if request.user.is_staff: + ctx["tts_url"] = reverse("api_tts_for_entry", args=[entry.id]) + return render(request, "entry_view.html", ctx) + + total = Entry.objects.count() + return render( + request, + "search.html", + { + "q": q, + "selected": selected, + "field_options": field_options, + "total": total, + "ran_search": True, + "result_count": 0, + }, + ) + + # --- existing search flow --- tokens = terms(q) fields = [f for f, sel in selected.items() if sel] or ["subject"]