Monorepo: consolidate 7 repos into one
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m5s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m5s
Combines shared, blog, market, cart, events, federation, and account into a single repository. Eliminates submodule sync, sibling model copying at build time, and per-app CI orchestration. Changes: - Remove per-app .git, .gitmodules, .gitea, submodule shared/ dirs - Remove stale sibling model copies from each app - Update all 6 Dockerfiles for monorepo build context (root = .) - Add build directives to docker-compose.yml - Add single .gitea/workflows/ci.yml with change detection - Add .dockerignore for monorepo build context - Create __init__.py for federation and account (cross-app imports)
This commit is contained in:
163
market/bp/browse/routes.py
Normal file
163
market/bp/browse/routes.py
Normal file
@@ -0,0 +1,163 @@
|
||||
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
|
||||
|
||||
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
|
||||
if not is_htmx_request():
|
||||
# Normal browser request: full page with layout
|
||||
html = await render_template("_types/market/index.html", **p_data)
|
||||
else:
|
||||
# HTMX request: main panel + OOB elements
|
||||
html = await render_template("_types/market/_oob_elements.html", **p_data)
|
||||
|
||||
return await make_response(html)
|
||||
|
||||
@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}
|
||||
|
||||
# Determine which template to use based on request type and pagination
|
||||
if not is_htmx_request():
|
||||
# Normal browser request: full page with layout
|
||||
html = await render_template("_types/browse/index.html", **full_context)
|
||||
elif product_info["page"] > 1:
|
||||
# HTMX pagination: just product cards + sentinel
|
||||
html = await render_template("_types/browse/_product_cards.html", **product_info)
|
||||
else:
|
||||
# HTMX navigation (page 1): main panel + OOB elements
|
||||
html = await render_template("_types/browse/_oob_elements.html", **full_context)
|
||||
|
||||
resp = await make_response(html)
|
||||
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}
|
||||
|
||||
# Determine which template to use based on request type and pagination
|
||||
if not is_htmx_request():
|
||||
# Normal browser request: full page with layout
|
||||
html = await render_template("_types/browse/index.html", **full_context)
|
||||
elif product_info["page"] > 1:
|
||||
# HTMX pagination: just product cards + sentinel
|
||||
html = await render_template("_types/browse/_product_cards.html", **product_info)
|
||||
else:
|
||||
html = await render_template("_types/browse/_oob_elements.html", **full_context)
|
||||
|
||||
resp = await make_response(html)
|
||||
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}
|
||||
|
||||
# Determine which template to use based on request type and pagination
|
||||
if not is_htmx_request():
|
||||
# Normal browser request: full page with layout
|
||||
html = await render_template("_types/browse/index.html", **full_context)
|
||||
elif product_info["page"] > 1:
|
||||
# HTMX pagination: just product cards + sentinel
|
||||
html = await render_template("_types/browse/_product_cards.html", **product_info)
|
||||
else:
|
||||
# HTMX navigation (page 1): main panel + OOB elements
|
||||
html = await render_template("_types/browse/_oob_elements.html", **full_context)
|
||||
|
||||
resp = await make_response(html)
|
||||
resp.headers["Hx-Push-Url"] = _current_url_without_page()
|
||||
return _vary(resp)
|
||||
|
||||
|
||||
|
||||
return browse_bp
|
||||
Reference in New Issue
Block a user