2026-01-13 20:58:05 -05:00
|
|
|
from django.urls import path
|
|
|
|
|
from . import views
|
|
|
|
|
|
|
|
|
|
urlpatterns = [
|
brief sprint C1: relocate Post + Line from dashboard → billboard (no behavior change) — TDD
The Post/Line models always read more like billboard tenants than dashboard ones (1st-person personal vs. 2nd-person provenance feed); the upcoming Brief model needs them in the billboard namespace as the canonical surface they FK into. C1 is a pure relocation w. zero new behavior: 789 ITs + 20 sky/Post FTs green against the moved code.
- billboard.models adds Post (owner + shared_with) + Line (text + post FK), schema mirroring the legacy dashboard models 1:1; Post.get_absolute_url now reverses to `billboard:view_post`.
- billboard.forms adds LineForm + ExistingPostLineForm (moved from dashboard.forms; dashboard/forms.py removed).
- billboard.views absorbs new_post / view_post / share_post / my_posts (templates rendered from apps/billboard/post.html + my_posts.html).
- billboard.urls adds the namespaced routes: /billboard/new-post, /billboard/post/<uuid>/, /billboard/post/<uuid>/share-post, /billboard/users/<uuid>/. dashboard.urls drops the corresponding entries.
- _applet-my-posts + _applet-new-post URL refs now use the billboard: namespace; templates/apps/dashboard/{post,my_posts}.html removed.
- api/serializers + api/views + api/tests/integrated/test_views imports flip dashboard.models → billboard.models (PostSerializer / PostDetailAPI / PostLinesAPI / PostsAPI all retain identifiers — the model rename to Brief lands in C2).
- dashboard/tests/integrated/test_{models,views,forms} + dashboard/tests/unit/test_{models,forms} swap imports; test_views URL strings flip /dashboard/post/ → /billboard/post/, /dashboard/new_post → /billboard/new-post, /dashboard/users/ → /billboard/users/, share_post → share-post (path) / billboard:share_post (reverser). Tests stay in dashboard.tests/ for now — relocation TBD.
- functional_tests/my_posts_page.py URL string flips to /billboard/users/.
- Auto-generated migrations: billboard/0001_initial (CreateModel Post + Line), dashboard/0003_remove_post_* (drops legacy Post + Line), drama/0004_alter_gameevent_verb (incidental — choices field caught up).
This commit drops the dashboard Post/Line tables w/o data preservation; user has confirmed staging-side wipe is acceptable. C2 introduces the Brief model + read-tracking + slide-down banner unification. C3 hooks Note-unlock + share-post-invite + magic-link / invalid-link `messages` calls into the new Brief / banner pipeline.
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 17:20:06 -04:00
|
|
|
# Post/Line CRUD has moved to apps.billboard.urls (`billboard:` namespace).
|
2026-03-05 14:45:55 -05:00
|
|
|
path('set_palette', views.set_palette, name='set_palette'),
|
2026-03-04 00:07:10 -05:00
|
|
|
path('set_profile', views.set_profile, name='set_profile'),
|
2026-03-05 14:45:55 -05:00
|
|
|
path('toggle_applets', views.toggle_applets, name="toggle_applets"),
|
2026-03-08 15:14:41 -04:00
|
|
|
path('wallet/', views.wallet, name='wallet'),
|
2026-03-11 00:58:24 -04:00
|
|
|
path('wallet/toggle-applets', views.toggle_wallet_applets, name='toggle_wallet_applets'),
|
2026-03-09 01:07:16 -04:00
|
|
|
path('wallet/setup-intent', views.setup_intent, name='setup_intent'),
|
|
|
|
|
path('wallet/save-payment-method', views.save_payment_method, name='save_payment_method'),
|
feat: shop PaymentIntent flow — `shop_buy` + `shop_confirm` + `stripe_webhook` — Chunk 3 of [[project-wallet-shop-expansion]]. Three-endpoint split per the locked Stripe design: webhook is authoritative for fulfillment (resilient to 3DS, browser closes, network drops); sync `/shop/confirm` is a best-effort UX speedup (fulfills immediately when Stripe.js confirms client-side, no waiting for webhook delivery); both call `Purchase.fulfill()` which is idempotent — whichever lands first wins, the other becomes a no-op via the `status==SUCCEEDED` guard. **`POST /dashboard/wallet/shop/buy`** (form-encoded `shop_item_slug`): looks up active ShopItem (404 if missing/inactive); enforces `max_owned` via `is_available_for(user)` (409 if cap hit, eg already-owned BAND); requires a saved PaymentMethod (402 otherwise — picks most-recent via `order_by('-pk').first()` per the open-Q note in the scope doc); creates Stripe PaymentIntent (amount=item.price_cents, currency=usd, customer=user.stripe_customer_id, payment_method=pm.stripe_pm_id, automatic_payment_methods={enabled, allow_redirects=never} for in-window 3DS); creates `Purchase` w. pi.id; backfills pi.metadata.purchase_id via `PaymentIntent.modify` so the webhook handler can resolve back to the row; returns `{client_secret, purchase_id}` JSON for Stripe.js `confirmCardPayment`. **`POST /dashboard/wallet/shop/confirm`** (form-encoded `purchase_id`): retrieves PI from Stripe, if `status=='succeeded'` calls `purchase.fulfill()`; returns `{status}` JSON. 404 if the purchase doesn't belong to `request.user`. Idempotent — re-firing after fulfill is a safe no-op. **`POST /stripe/webhook`** (csrf_exempt, mounted at root `/stripe/webhook` so the URL stays stable across app-routing refactors w. Stripe's dashboard config): verifies signature via `stripe.Webhook.construct_event` against `STRIPE_WEBHOOK_SECRET` env var (400 on mismatch — Stripe won't retry on 4xx, only 5xx); on `payment_intent.succeeded` looks up Purchase by `metadata.purchase_id` w. fall-back to `stripe_payment_intent_id` (both unique). Unknown event types are no-op 200 (Stripe sends `charge.dispute.created` etc. + would retry indefinitely on 5xx). New `STRIPE_WEBHOOK_SECRET = os.environ.get(...)` setting; user swaps it on staging+prod per the live-mode env-var-only decision. TDD — 17 ITs in `test_shop_views.py` across 3 classes: `ShopBuyViewTest` (7 cases — login required, success path creates PI + Purchase w. correct shape, PI.create called w. correct args, unknown slug 404, inactive item 404, max_owned 409, no PM 402); `ShopConfirmViewTest` (5 cases — login required, succeeded PI triggers fulfill, processing PI leaves PENDING, idempotent on already-SUCCEEDED, other user's purchase 404); `StripeWebhookViewTest` (5 cases — sig mismatch 400, succeeded event triggers fulfill, unknown event type 2xx no-op, duplicate delivery idempotent, unknown purchase_id 2xx no-op). All Stripe API calls mocked via `mock.patch('apps.dashboard.views.stripe')`. 1208 IT/UT green
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 00:42:09 -04:00
|
|
|
path('wallet/shop/buy', views.shop_buy, name='shop_buy'),
|
|
|
|
|
path('wallet/shop/confirm', views.shop_confirm, name='shop_confirm'),
|
2026-05-30 14:51:21 -04:00
|
|
|
path('wallet/shop/claim', views.shop_claim_free, name='shop_claim_free'),
|
2026-03-15 01:17:09 -04:00
|
|
|
path('kit-bag/', views.kit_bag, name='kit_bag'),
|
2026-04-16 03:03:19 -04:00
|
|
|
path('sky/', views.sky_view, name='sky'),
|
2026-04-21 20:07:40 -04:00
|
|
|
path('sky/preview', views.sky_preview, name='sky_preview'),
|
|
|
|
|
path('sky/save', views.sky_save, name='sky_save'),
|
sky.html: DEL btn at wheel center; async SAVE SKY transitions into saved state without reload; pre-save hides wheel-col so form+SAVE SKY stay centered — TDD
DEL btn (.btn-danger, "Forget sky?" data-confirm wired to the global #id_guard_portal) sits absolutely centered inside .sky-wheel-col; OK submits a POST to the new sky_delete view, which clears every sky_* field on the User model & redirects back to /dashboard/sky/.
The sky.html aperture is now uniform across saved/unsaved: form-col is always flex-column align-center justify-center so the fields + SAVE SKY pair sits visually centered. body.sky-saved adds *only* the snap-binary scroll layer (scroll-snap-type:y, modal-body display:contents, cols min-height:100% scroll-snap-align:start, wheel-col aspect-ratio cap released, form-col flex:0 0 auto so the snap basis wins) — the column-stacking is no longer gated.
Async save: SAVE SKY's success branch now calls _activateSavedState(), which adds body.sky-saved, draws the wheel from _lastChartData, pins overlay.scrollTop to the form section's offsetTop, then runs the existing _scrollApertureToTop ease-out so the wheel reveals from above instead of replacing the form with a hard cut. The wheel preview that previously redrew during typing is now gated on _savedSky — pre-first-save typing fetches the chart data (so SAVE SKY enables) but does not render the wheel, mirroring the My Sky applet's "no wheel until saved" UX. The in-room PICK SKY overlay (_sky_overlay.html) still previews live, deliberately untouched.
Pre-save the wheel-col is hidden via `body:not(.sky-saved) .sky-page .sky-wheel-col { display: none }`, so the empty SVG can't shunt the form below the fold (& the DEL btn rides the same selector since it lives inside .sky-wheel-col).
Tests: SkyDeleteTest IT class (5: clears fields, redirects, 405 on GET, login required, preserves unrelated user fields). MySkyDeleteFlowTest FT class (3: DEL btn visibility gated on sky data, NVM dismisses w. data intact, OK clears + reverts body class). MySkyAsyncSaveTest FT (1: fresh user → SAVE SKY → body picks up sky-saved, wheel SVG populates, DEL btn becomes visible — all without a page reload). All 13 sky FTs + sky ITs green; existing MySkyApertureSnapScrollTest & MySkyTimezoneRefreshTest still pass.
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 13:07:56 -04:00
|
|
|
path('sky/delete', views.sky_delete, name='sky_delete'),
|
rename natus → sky across the codebase — natal chart abstraction is now sky throughout, since chart inputs aren't birthday-gated
Mechanical rename: 5 files (sky-wheel.js, _sky.scss, _sky_overlay.html, SkyWheelSpec.js x2), 24 in-place edits across templates/views/urls/SCSS/JS/tests/CLAUDE.md. URL names epic:natus_save → epic:sky_save (epic namespaced, no clash w. dashboard:sky_save), JS module NatusWheel → SkyWheel, DOM ids id_natus_* → id_sky_*, BEM classes natus-* → sky-*, dashboard sky_natus_data/sky_natus_preview collapsed to sky_data/sky_preview_data. No DB migration needed (User.sky_chart_data + GameEvent.SKY_SAVED already used sky-prefix). 778 ITs + Jasmine green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:36:15 -04:00
|
|
|
path('sky/data', views.sky_data, name='sky_data'),
|
pronouns: per-user pronouns ideology + Pronouns applet on Game Kit; provenance prose uses actor.pronouns at render time — TDD
- User.pronouns CharField w. choices=[pluralism (default), bawlmorese, misogyny, misandry, misanthropy] + pronoun_subj/obj/poss properties; PRONOUN_TABLE single source of truth in apps.lyric.models; mig 0002_user_pronouns
- drama.GameEvent.to_prose() drops module-level PRONOUN_* constants; SIG_READY/SIG_UNREADY/ROLE_SELECTED now resolve poss/subj from self.actor.pronouns at render time, so flipping a user's preference rewrites all their existing scroll prose; default actor → "their"
- SIG_READY prose strips a leading "The " from card_name so "the The Wanderer" reads "the Wanderer" and "the Engraven The Nomad" reads "the Engraven Nomad"; minor arcana ("Maid of Brands") untouched
- new applets/0005 seeds 'pronouns' applet (3x3, game-kit, default visible); _game_kit_sections.html grows a #id_gk_pronouns block w. 5 .gk-pronoun-card items labeled by ideology slug (italic) and tagged data-pronoun + data-trio
- card click → window.showGuard(card, "Set pronoun preference?<span class='guard-pronoun-trio'>{trio}</span>", commitCb); on OK fetches POST /dashboard/set-pronouns w. CSRF cookie + reloads so .active class moves and provenance prose re-renders; NVM dismisses
- dashboard.set_pronouns view (POST-only, login_required, 204/400/405) at /dashboard/set-pronouns; rejects choices not in PRONOUN_TABLE
- _game-kit.scss extends shared card rule to .gk-pronoun-card w. .active fill state + italic ideology label; #id_guard_portal .guard-pronoun-trio styled small/dim/centered under the question
- billscroll aperture: padding-right 0.75rem on #id_drama_scroll inside .applet-scroll so the timestamp column no longer sits beneath the scrollbar
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 01:11:40 -04:00
|
|
|
path('set-pronouns', views.set_pronouns, name='set_pronouns'),
|
2026-01-13 20:58:05 -05:00
|
|
|
]
|