From 6a1d3beef9806a029e537b190b3b39033f0ccc4c Mon Sep 17 00:00:00 2001 From: Joshua Laymon Date: Sun, 7 Sep 2025 18:44:10 +0000 Subject: [PATCH] Update web/core/views.py --- web/core/views.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/web/core/views.py b/web/core/views.py index a2a478c..57bcbf6 100644 --- a/web/core/views.py +++ b/web/core/views.py @@ -121,7 +121,7 @@ def search_page(request): - AND across tokens, OR across the selected fields Special power term: - - 'invalidscripture' -> returns only entries whose scripture would trigger red pills (validation warnings) + - 'invalidscripture' -> entries whose Scripture would show red (invalid) """ default_fields = { "subject": True, @@ -147,17 +147,27 @@ def search_page(request): q = (request.GET.get("q") or "").strip() if q: - # ✨ Special command: list entries whose Scripture validation would fail (red pills) + # ===== SPECIAL POWER TERM ===== if q.lower() == "invalidscripture": - qs = Entry.objects.exclude(scripture_raw="").only("id", "scripture_raw", "date_added") + # A simple server-side validity check that mirrors the front-end idea: + # each piece must look like " " + book_ch_re = re.compile(r"^.+?\s+\d{1,3}(?::\s*.+)?$") + 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: + qs_all = Entry.objects.exclude(scripture_raw="").only("id", "scripture_raw", "date_added") + for e in qs_all.iterator(chunk_size=1000): + original = (e.scripture_raw or "").strip() + norm, warns = normalize_scripture_field(original) + + # Split into pieces as the UI does + pieces = [p.strip() for p in original.split(";") if p.strip()] + # Invalid if: + # - normalizer produced warnings (e.g., verses but no book), OR + # - any piece fails " " quick check + any_bad_shape = any(not book_ch_re.match(p) for p in pieces) + if warns or any_bad_shape: 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") @@ -195,8 +205,8 @@ def search_page(request): "result_count": 0, }, ) + # ===== END SPECIAL TERM ===== - # --- existing search flow --- tokens = terms(q) fields = [f for f, sel in selected.items() if sel] or ["subject"] @@ -233,19 +243,15 @@ def search_page(request): request.session["result_ids"] = ids count = len(ids) - # Ensure highlighter data is available BEFORE navigating to entry_view request.session["last_search"] = {"q": q, "fields": fields} - request.session.modified = True # be explicit so it’s flushed + request.session.modified = True if count: entry = Entry.objects.get(pk=ids[0]) ctx = entry_context(entry, ids) ctx.update({"from_search": True}) - - # 🔽 ADD THIS 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()