From b933daffd9fdc22bc9e26f0863ec07a5e5ab5965 Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Mon, 9 Feb 2026 07:19:11 -0500 Subject: [PATCH] Forge ring on first access, add /s/{shop_id}/ring.json endpoint Existing shops had no ring until a product edit triggered it. Now watch_json and server-rendered views forge the ring on first access if empty. Added ring.json diagnostic endpoint to inspect a shop's discovery ring state. --- make_post_sell/routes.py | 1 + make_post_sell/static/css/common.css | 15 +++++++++++-- make_post_sell/views/content.py | 7 ++++-- make_post_sell/views/product.py | 6 +++-- make_post_sell/views/watch.py | 33 +++++++++++++++++++++++----- 5 files changed, 50 insertions(+), 12 deletions(-) diff --git a/make_post_sell/routes.py b/make_post_sell/routes.py index 4092935..cd5c27d 100644 --- a/make_post_sell/routes.py +++ b/make_post_sell/routes.py @@ -171,6 +171,7 @@ def includeme(config): config.add_route("player", "/player/{product_id}") config.add_route("player_json", "/player/{product_id}/json") config.add_route("watch_json", "/watch/{product_id}/json") + config.add_route("discovery_ring_json", "/s/{shop_id}/ring.json") config.add_route("random", "/random") config.add_route("tv", "/tv") diff --git a/make_post_sell/static/css/common.css b/make_post_sell/static/css/common.css index 94fe185..733e459 100644 --- a/make_post_sell/static/css/common.css +++ b/make_post_sell/static/css/common.css @@ -1595,7 +1595,7 @@ textarea.markup-editor-textarea { } div.message-ribbon { - display: block; + display: grid; } /* Desktop, NOT watch mode: full nav is sticky */ @@ -2620,7 +2620,6 @@ textarea { /* Watch mode: sticky video within tall left wrapper */ .watch-mode .product-images { position: sticky; - top: 0; z-index: 10; background: var(--bg-primary, #ffffff); overflow: hidden; @@ -2758,6 +2757,18 @@ textarea { cursor: pointer; } +.watch-direction-label input { + display: none; +} + +.watch-direction-label input:checked + .autoplay-slider { + background: var(--blue-color, #98b6fa); +} + +.watch-direction-label input:checked + .autoplay-slider::after { + transform: translateX(16px); +} + .direction-label-text { font-size: 0.85em; color: var(--text-muted, #999); diff --git a/make_post_sell/views/content.py b/make_post_sell/views/content.py index dea0693..147045f 100644 --- a/make_post_sell/views/content.py +++ b/make_post_sell/views/content.py @@ -74,12 +74,15 @@ def content(request): related_products = [] if product.shop.watch_mode_enabled: + from ..models.product import get_ring_related_products, get_related_products + from ..models.shop import reforge_discovery_ring ring = product.shop.discovery_ring + if not ring: + ring = reforge_discovery_ring(product.shop) + request.dbsession.flush() if ring: - from ..models.product import get_ring_related_products related_products = get_ring_related_products(product, ring) else: - from ..models.product import get_related_products related_products = get_related_products(product) return { diff --git a/make_post_sell/views/product.py b/make_post_sell/views/product.py index bdd7d72..5a7e83a 100644 --- a/make_post_sell/views/product.py +++ b/make_post_sell/views/product.py @@ -94,12 +94,14 @@ def product(request): related_products = [] if product.shop.watch_mode_enabled: + from ..models.product import get_ring_related_products, get_related_products ring = product.shop.discovery_ring + if not ring: + ring = reforge_discovery_ring(product.shop) + request.dbsession.flush() if ring: - from ..models.product import get_ring_related_products related_products = get_ring_related_products(product, ring) else: - from ..models.product import get_related_products related_products = get_related_products(product) return { diff --git a/make_post_sell/views/watch.py b/make_post_sell/views/watch.py index 981bdaf..6a122a3 100644 --- a/make_post_sell/views/watch.py +++ b/make_post_sell/views/watch.py @@ -1,7 +1,7 @@ from pyramid.view import view_config from ..models.product import get_media_type, get_related_products, get_ring_related_products -from ..models.shop import reforge_discovery_ring +from ..models.shop import reforge_discovery_ring, get_shop_by_id @view_config(route_name="watch_json", renderer="json") @@ -76,13 +76,15 @@ def watch_json(request): p_or_c = "p" if product.is_sellable else "c" canonical_url = f"/{p_or_c}/{product.id}/{product.slug}" - # Related products via discovery ring (fallback to stem-based) + # Related products via discovery ring (forge on first access if needed) ring = request.shop.discovery_ring + if not ring: + ring = reforge_discovery_ring(request.shop) + request.dbsession.flush() + if ring and str(product.id) not in ring: + ring = reforge_discovery_ring(request.shop) + request.dbsession.flush() if ring: - if str(product.id) not in ring: - # Product missing from ring — reforge inline - ring = reforge_discovery_ring(request.shop) - request.dbsession.flush() related = get_ring_related_products(product, ring) else: related = get_related_products(product) @@ -119,3 +121,22 @@ def watch_json(request): "related": related_data, "ring": ring, } + + +@view_config(route_name="discovery_ring_json", renderer="json") +def discovery_ring_json(request): + """Public JSON endpoint to inspect the discovery ring for a shop.""" + shop_id = request.matchdict.get("shop_id") + shop = get_shop_by_id(request.dbsession, shop_id) + if not shop: + request.response.status_int = 404 + return {"error": "Shop not found"} + + ring = shop.discovery_ring + return { + "shop_id": str(shop.id), + "shop_name": shop.name, + "watch_mode_enabled": shop.watch_mode_enabled, + "ring_length": len(ring), + "ring": ring, + }