Rename all sexp directories, files, identifiers, and references to sx. artdag/ excluded (separate media processing DSL). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
180 lines
5.5 KiB
Python
180 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
|
|
from quart import (
|
|
g,
|
|
Blueprint,
|
|
abort,
|
|
render_template,
|
|
render_template_string,
|
|
make_response,
|
|
current_app,
|
|
)
|
|
from shared.config import config
|
|
from .services.nav import category_context, get_nav
|
|
from .services.blacklist.category import is_category_blocked
|
|
|
|
from .services import (
|
|
_hx_fragment_request,
|
|
_productInfo,
|
|
_vary,
|
|
_current_url_without_page,
|
|
)
|
|
|
|
from shared.browser.app.redis_cacher import cache_page
|
|
from shared.browser.app.utils.htmx import is_htmx_request
|
|
from shared.sx.helpers import sx_response
|
|
|
|
def register():
|
|
browse_bp = Blueprint("browse", __name__)
|
|
|
|
from .. import register_product
|
|
browse_bp.register_blueprint(
|
|
register_product(),
|
|
)
|
|
|
|
@browse_bp.get("/")
|
|
@cache_page(tag="browse")
|
|
async def home():
|
|
"""
|
|
Market landing page.
|
|
Uses the post data hydrated by the app-level before_request (g.post_data).
|
|
"""
|
|
p_data = getattr(g, "post_data", None) or {}
|
|
|
|
# Determine which template to use based on request type
|
|
from shared.sx.page import get_template_context
|
|
from sx.sx_components import render_market_home_page, render_market_home_oob
|
|
|
|
ctx = await get_template_context()
|
|
ctx.update(p_data)
|
|
if not is_htmx_request():
|
|
html = await render_market_home_page(ctx)
|
|
return await make_response(html)
|
|
else:
|
|
sx_src = await render_market_home_oob(ctx)
|
|
return sx_response(sx_src)
|
|
|
|
@browse_bp.get("/all/")
|
|
@cache_page(tag="browse")
|
|
async def browse_all():
|
|
"""
|
|
Browse all products across all categories.
|
|
Renders full page or just product cards (HTMX pagination fragment).
|
|
"""
|
|
market = getattr(g, "market", None)
|
|
market_id = market.id if market else None
|
|
nav = await get_nav(g.s, market_id=market_id)
|
|
ctx = {
|
|
"category_label": "All Products",
|
|
"top_slug": "all",
|
|
"sub_slug": None,
|
|
}
|
|
|
|
product_info = await _productInfo()
|
|
full_context = {**product_info, **ctx}
|
|
|
|
from shared.sx.page import get_template_context
|
|
from sx.sx_components import render_browse_page, render_browse_oob, render_browse_cards
|
|
|
|
tctx = await get_template_context()
|
|
tctx.update(full_context)
|
|
if not is_htmx_request():
|
|
html = await render_browse_page(tctx)
|
|
resp = await make_response(html)
|
|
elif product_info["page"] > 1:
|
|
tctx.update(product_info)
|
|
sx_src = await render_browse_cards(tctx)
|
|
resp = sx_response(sx_src)
|
|
else:
|
|
sx_src = await render_browse_oob(tctx)
|
|
resp = sx_response(sx_src)
|
|
|
|
resp.headers["Hx-Push-Url"] = _current_url_without_page()
|
|
return _vary(resp)
|
|
|
|
|
|
@browse_bp.get("/<top_slug>/")
|
|
@cache_page(tag="browse")
|
|
async def browse_top(top_slug: str):
|
|
"""
|
|
Browse by top-level category (e.g. /fruit).
|
|
404 if category not in allowed list or is blocked.
|
|
"""
|
|
REVERSE_CATEGORY = {v: k for k, v in config()["categories"]["allow"].items()}
|
|
if top_slug not in REVERSE_CATEGORY:
|
|
abort(404)
|
|
if is_category_blocked(top_slug):
|
|
abort(404)
|
|
|
|
market = getattr(g, "market", None)
|
|
market_id = market.id if market else None
|
|
nav = await get_nav(g.s, market_id=market_id)
|
|
ctx = category_context(top_slug, None, nav)
|
|
|
|
product_info = await _productInfo(top_slug)
|
|
full_context = {**product_info, **ctx}
|
|
|
|
from shared.sx.page import get_template_context
|
|
from sx.sx_components import render_browse_page, render_browse_oob, render_browse_cards
|
|
|
|
tctx = await get_template_context()
|
|
tctx.update(full_context)
|
|
if not is_htmx_request():
|
|
html = await render_browse_page(tctx)
|
|
resp = await make_response(html)
|
|
elif product_info["page"] > 1:
|
|
tctx.update(product_info)
|
|
sx_src = await render_browse_cards(tctx)
|
|
resp = sx_response(sx_src)
|
|
else:
|
|
sx_src = await render_browse_oob(tctx)
|
|
resp = sx_response(sx_src)
|
|
|
|
resp.headers["Hx-Push-Url"] = _current_url_without_page()
|
|
return _vary(resp)
|
|
|
|
|
|
@browse_bp.get("/<top_slug>/<sub_slug>/")
|
|
@cache_page(tag="browse")
|
|
async def browse_sub(top_slug: str, sub_slug: str):
|
|
"""
|
|
Browse by subcategory (e.g. /fruit/citrus).
|
|
404 if blocked or unknown.
|
|
"""
|
|
REVERSE_CATEGORY = {v: k for k, v in config()["categories"]["allow"].items()}
|
|
if top_slug not in REVERSE_CATEGORY:
|
|
abort(404)
|
|
if is_category_blocked(top_slug, sub_slug):
|
|
abort(404)
|
|
|
|
market = getattr(g, "market", None)
|
|
market_id = market.id if market else None
|
|
nav = await get_nav(g.s, market_id=market_id)
|
|
ctx = category_context(top_slug, sub_slug, nav)
|
|
|
|
product_info = await _productInfo(top_slug, sub_slug)
|
|
full_context = {**product_info, **ctx}
|
|
|
|
from shared.sx.page import get_template_context
|
|
from sx.sx_components import render_browse_page, render_browse_oob, render_browse_cards
|
|
|
|
tctx = await get_template_context()
|
|
tctx.update(full_context)
|
|
if not is_htmx_request():
|
|
html = await render_browse_page(tctx)
|
|
resp = await make_response(html)
|
|
elif product_info["page"] > 1:
|
|
tctx.update(product_info)
|
|
sx_src = await render_browse_cards(tctx)
|
|
resp = sx_response(sx_src)
|
|
else:
|
|
sx_src = await render_browse_oob(tctx)
|
|
resp = sx_response(sx_src)
|
|
|
|
resp.headers["Hx-Push-Url"] = _current_url_without_page()
|
|
return _vary(resp)
|
|
|
|
|
|
|
|
return browse_bp |