This repository has been archived on 2026-02-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
market/bp/browse/services/nav.py
giles 05cba16cef
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 43s
Fix category highlighting and revert current_local_href breakage
- Update shared submodule: category selector uses slug comparison
  instead of current_local_href for active state
- Keep current_local_href commented out in category_context() to
  avoid overriding the base template value used by brand filters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:29:06 +00:00

164 lines
5.2 KiB
Python

from __future__ import annotations
import time
import re
from typing import Dict, List, Tuple, Optional
from urllib.parse import urlparse, urljoin
from shared.config import config
from . import db_backend as cb
from .blacklist.category import is_category_blocked # Reverse map: slug -> label
# ------------------ Caches ------------------
_nav_cache: Dict = {}
_nav_cache_ts: float = 0.0
_nav_ttl_seconds = 60 * 60 * 6 # 6 hours
def _now() -> float:
try:
return now() # type: ignore[name-defined]
except Exception:
return time.time()
def extract_sub_slug(href: str, top_slug: str) -> Optional[str]:
p = urlparse(href)
parts = [x for x in (p.path or "").split("/") if x]
if len(parts) >= 2 and parts[0].lower() == top_slug.lower():
sub = parts[1]
if sub.lower().endswith((".html", ".htm")):
sub = re.sub(r"\.(html?|HTML?)$", "", sub)
return sub
return None
def group_by_category(slug_to_links: Dict[str, List[Tuple[str, str]]]) -> Dict[str, Dict]:
nav = {"cats": {}}
for label, slug in config()["categories"]["allow"].items():
top_href = urljoin(config()["base_url"], f"/{slug}")
subs = []
for text, href in slug_to_links.get(slug, []):
sub_slug = extract_sub_slug(href, slug)
if sub_slug:
subs.append({
"name": text,
"href": href,
"slug": sub_slug,
# no count here yet in this path
})
subs.sort(key=lambda x: x["name"].lower())
nav["cats"][label] = {"href": top_href, "slug": slug, "subs": subs}
nav = _apply_category_blacklist(nav)
return nav
async def get_nav(session, market_id=None) -> Dict[str, Dict]:
"""
Return navigation structure; annotate each sub with product counts.
Uses snapshot for offline behaviour.
"""
global _nav_cache, _nav_cache_ts
now_ts = _now()
# load from snapshot
nav = await cb.db_nav(session, market_id=market_id)
# inject counts for each subcategory (and for top-level too if you like)
for label, cat in (nav.get("cats") or {}).items():
top_slug = cat.get("slug")
if not top_slug:
continue
# Counts for subs
new_subs = []
for s in cat.get("subs", []):
s.get("slug")
#if not sub_slug:
# s_count = 0
#else:
# s_count = await cb.db_count_products_in_sub(session,top_slug, sub_slug)
#print('sub', s_count)
new_subs.append({
**s,
#"count": s_count,
})
cat["subs"] = new_subs
_nav_cache = nav
_nav_cache_ts = now_ts
nav = _apply_category_blacklist(nav)
return nav
def category_context(top_slug: Optional[str], sub_slug: Optional[str], nav: Dict[str, Dict]):
"""Build template context for a category/subcategory page."""
def _order_subs_selected_first(subs, sub_slug: str | None):
"""Return subs with the selected subcategory (by slug) first."""
if not subs or not sub_slug:
return subs
head = [s for s in subs if sub_slug and sub_slug.lower() == s['slug']]
tail = [s for s in subs if not (sub_slug and sub_slug.lower() == s['slug'])]
return head + tail
REVERSE_CATEGORY = {v: k for k, v in config()["categories"]["allow"].items()}
label = REVERSE_CATEGORY.get(top_slug)
cat = nav["cats"].get(label) or {}
top_suma_href = cat.get("href") or urljoin(config()["base_url"], f"/{top_slug}")
top_local_href = f"{top_slug}"
# total products in this top-level category (all subs combined / top-level listing)
top_count = cat.get("count", 0)
subs = []
for s in cat.get("subs", []):
subs.append({
"name": s["name"],
"slug": s.get("slug"),
"local_href": f"{top_slug}/{s.get('slug')}",
"suma_href": s["href"],
"count": s.get("count", 0), # per-subcategory product count
})
current_local_href = (
f"{top_slug}/{sub_slug}" if sub_slug
else f"{top_slug}" if top_slug
else ""
)
return {
"category_label": label,
"top_slug": top_slug,
"sub_slug": sub_slug,
"top_suma_href": top_suma_href,
"top_local_href": top_local_href,
# 👇 expose total count for the parent category
"top_count": top_count,
# list of subcategories, each with its own count
"subs_local": _order_subs_selected_first(subs, sub_slug),
#"current_local_href": current_local_href,
}
def _apply_category_blacklist(nav: Dict[str, Dict]) -> Dict[str, Dict]:
cats = nav.get("cats", {})
out = {"cats": {}}
for label, data in cats.items():
top = (data or {}).get("slug")
if not top or is_category_blocked(top):
continue
# filter subs
subs = []
for s in (data.get("subs") or []):
sub_slug = s.get("slug")
if sub_slug and not is_category_blocked(top, sub_slug):
subs.append(s)
# keep everything else (including counts)
out["cats"][label] = {**data, "subs": subs}
return out