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>
This commit is contained in:
@@ -619,13 +619,13 @@ class SkySaveViewTest(TestCase):
|
||||
self.assertAlmostEqual(self.user.sky_chart_data["houses"]["asc"], 123.4)
|
||||
|
||||
|
||||
class SkyNatusDataViewTest(TestCase):
|
||||
class SkyDataViewTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create(email="disco@test.io")
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def test_returns_stored_chart_with_asc_preserved(self):
|
||||
"""sky_natus_data returns sky_chart_data — asc must match what was saved."""
|
||||
"""sky_data returns sky_chart_data — asc must match what was saved."""
|
||||
stored = {
|
||||
"planets": {},
|
||||
"houses": {"cusps": [float(i * 30) for i in range(12)], "asc": 236.1, "mc": 159.1},
|
||||
|
||||
@@ -17,6 +17,6 @@ urlpatterns = [
|
||||
path('sky/', views.sky_view, name='sky'),
|
||||
path('sky/preview', views.sky_preview, name='sky_preview'),
|
||||
path('sky/save', views.sky_save, name='sky_save'),
|
||||
path('sky/data', views.sky_natus_data, name='sky_natus_data'),
|
||||
path('sky/data', views.sky_data, name='sky_data'),
|
||||
path('set-pronouns', views.set_pronouns, name='set_pronouns'),
|
||||
]
|
||||
|
||||
@@ -287,7 +287,7 @@ def save_payment_method(request):
|
||||
|
||||
# ── My Sky (personal natal chart) ────────────────────────────────────────────
|
||||
|
||||
def _sky_natus_preview(request):
|
||||
def _sky_preview_data(request):
|
||||
"""Shared preview logic — proxies to PySwiss, no DB writes."""
|
||||
date_str = request.GET.get('date')
|
||||
time_str = request.GET.get('time', '12:00')
|
||||
@@ -380,7 +380,7 @@ def sky_view(request):
|
||||
|
||||
@login_required(login_url="/")
|
||||
def sky_preview(request):
|
||||
return _sky_natus_preview(request)
|
||||
return _sky_preview_data(request)
|
||||
|
||||
|
||||
@login_required(login_url="/")
|
||||
@@ -440,7 +440,7 @@ def sky_save(request):
|
||||
|
||||
|
||||
@login_required(login_url="/")
|
||||
def sky_natus_data(request):
|
||||
def sky_data(request):
|
||||
user = request.user
|
||||
if not user.sky_chart_data:
|
||||
return HttpResponse(status=404)
|
||||
|
||||
@@ -653,7 +653,7 @@ class Character(models.Model):
|
||||
on_delete=models.SET_NULL, related_name='character_significators',
|
||||
)
|
||||
|
||||
# ── natus input (what the gamer entered) ─────────────────────────────
|
||||
# ── sky input (what the gamer entered) ─────────────────────────────
|
||||
birth_dt = models.DateTimeField(null=True, blank=True) # UTC
|
||||
birth_lat = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
||||
birth_lon = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
||||
@@ -662,7 +662,7 @@ class Character(models.Model):
|
||||
max_length=1, choices=HOUSE_SYSTEM_CHOICES, default=PORPHYRY,
|
||||
)
|
||||
|
||||
# ── computed natus snapshot (full PySwiss response) ───────────────────
|
||||
# ── computed sky snapshot (full PySwiss response) ───────────────────
|
||||
chart_data = models.JSONField(null=True, blank=True)
|
||||
|
||||
# ── celtic cross spread (added at PICK SEA) ───────────────────────────
|
||||
|
||||
@@ -1933,16 +1933,16 @@ class SelectSigViewTest(TestCase):
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
|
||||
# ── natus_preview (epic) ──────────────────────────────────────────────────────
|
||||
# ── sky_preview (epic) ──────────────────────────────────────────────────────
|
||||
|
||||
class NatusPreviewViewTest(TestCase):
|
||||
class SkyPreviewViewTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create(email="pc@natus.io")
|
||||
self.user = User.objects.create(email="pc@sky.io")
|
||||
self.client.force_login(self.user)
|
||||
self.room, _ = _make_sig_room(self.user)
|
||||
self.room.table_status = Room.SKY_SELECT
|
||||
self.room.save()
|
||||
self.url = reverse("epic:natus_preview", kwargs={"room_id": self.room.id})
|
||||
self.url = reverse("epic:sky_preview", kwargs={"room_id": self.room.id})
|
||||
|
||||
def test_missing_params_returns_400(self):
|
||||
response = self.client.get(self.url, {"date": "1990-06-15"})
|
||||
@@ -2025,16 +2025,16 @@ class TarotDealViewTest(TestCase):
|
||||
)
|
||||
|
||||
|
||||
# ── natus_save (epic) ─────────────────────────────────────────────────────────
|
||||
# ── sky_save (epic) ─────────────────────────────────────────────────────────
|
||||
|
||||
class NatusSaveViewTest(TestCase):
|
||||
class SkySaveViewTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create(email="pc@natussave.io")
|
||||
self.user = User.objects.create(email="pc@skysave.io")
|
||||
self.client.force_login(self.user)
|
||||
self.room, _ = _make_sig_room(self.user)
|
||||
self.room.table_status = Room.SKY_SELECT
|
||||
self.room.save()
|
||||
self.url = reverse("epic:natus_save", kwargs={"room_id": self.room.id})
|
||||
self.url = reverse("epic:sky_save", kwargs={"room_id": self.room.id})
|
||||
|
||||
def _post(self, payload):
|
||||
import json as _json
|
||||
@@ -2134,7 +2134,7 @@ class NatusSaveViewTest(TestCase):
|
||||
|
||||
def test_confirm_with_dict_shaped_elements_extracts_count(self):
|
||||
"""Some chart payloads enrich each element to {count, contributors};
|
||||
natus_save should read .count rather than treating the dict as a value."""
|
||||
sky_save should read .count rather than treating the dict as a value."""
|
||||
from apps.drama.models import GameEvent
|
||||
chart = {
|
||||
"elements": {
|
||||
@@ -2156,7 +2156,7 @@ class NatusSaveViewTest(TestCase):
|
||||
self.assertEqual(event.data.get("top_capacitors"), ["Ardor"])
|
||||
|
||||
def test_confirm_copies_seat_significator_to_character(self):
|
||||
"""natus_save with action=confirm copies seat.significator onto Character."""
|
||||
"""sky_save with action=confirm copies seat.significator onto Character."""
|
||||
earthman, _ = DeckVariant.objects.get_or_create(
|
||||
slug="earthman", defaults={"name": "Earthman Deck", "card_count": 108}
|
||||
)
|
||||
|
||||
@@ -25,8 +25,8 @@ urlpatterns = [
|
||||
path('room/<uuid:room_id>/abandon', views.abandon_room, name='abandon_room'),
|
||||
path('room/<uuid:room_id>/tarot/', views.tarot_deck, name='tarot_deck'),
|
||||
path('room/<uuid:room_id>/tarot/deal', views.tarot_deal, name='tarot_deal'),
|
||||
path('room/<uuid:room_id>/natus/preview', views.natus_preview, name='natus_preview'),
|
||||
path('room/<uuid:room_id>/natus/save', views.natus_save, name='natus_save'),
|
||||
path('room/<uuid:room_id>/sky/preview', views.sky_preview, name='sky_preview'),
|
||||
path('room/<uuid:room_id>/sky/save', views.sky_save, name='sky_save'),
|
||||
path('room/<uuid:room_id>/sea/partial', views.sea_partial, name='sea_partial'),
|
||||
path('room/<uuid:room_id>/sea/deck', views.sea_deck, name='sea_deck'),
|
||||
]
|
||||
|
||||
@@ -25,7 +25,7 @@ def stack_reversal_probability(user=None, room=None):
|
||||
|
||||
|
||||
|
||||
# Element key → in-game capacitor name (mirrors ELEMENT_INFO in natus-wheel.js).
|
||||
# Element key → in-game capacitor name (mirrors ELEMENT_INFO in sky-wheel.js).
|
||||
# Used by the SKY_SAVED provenance event to render prose like
|
||||
# "yields them a unique Ardor capacity."
|
||||
ELEMENT_CAPACITOR_NAMES = {
|
||||
|
||||
@@ -975,10 +975,10 @@ def tarot_deal(request, room_id):
|
||||
})
|
||||
|
||||
|
||||
# ── Natus (natal chart) ───────────────────────────────────────────────────────
|
||||
# ── Sky (natal chart) ───────────────────────────────────────────────────────
|
||||
|
||||
@login_required
|
||||
def natus_preview(request, room_id):
|
||||
def sky_preview(request, room_id):
|
||||
"""Proxy GET to PySwiss /api/chart/ and augment with distinction counts.
|
||||
|
||||
Query params:
|
||||
@@ -1064,7 +1064,7 @@ def natus_preview(request, room_id):
|
||||
|
||||
|
||||
@login_required
|
||||
def natus_save(request, room_id):
|
||||
def sky_save(request, room_id):
|
||||
"""Create or update the draft Character for the requesting gamer's seat.
|
||||
|
||||
POST body (JSON):
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* natus-wheel.js — Self-contained D3 natal-chart module.
|
||||
* sky-wheel.js — Self-contained D3 natal-chart module.
|
||||
*
|
||||
* Public API:
|
||||
* NatusWheel.draw(svgEl, data) — first render
|
||||
* NatusWheel.redraw(data) — live update (same SVG)
|
||||
* NatusWheel.clear() — empty the SVG
|
||||
* SkyWheel.draw(svgEl, data) — first render
|
||||
* SkyWheel.redraw(data) — live update (same SVG)
|
||||
* SkyWheel.clear() — empty the SVG
|
||||
*
|
||||
* `data` shape — matches the /epic/natus/preview/ proxy response:
|
||||
* `data` shape — matches the /epic/sky/preview/ proxy response:
|
||||
* {
|
||||
* planets: { Sun: { sign, degree, speed, retrograde }, … },
|
||||
* houses: { cusps: [f×12], asc: f, mc: f },
|
||||
@@ -28,7 +28,7 @@
|
||||
* already defined in the page; falls back to neutral colours if absent.
|
||||
*/
|
||||
|
||||
const NatusWheel = (() => {
|
||||
const SkyWheel = (() => {
|
||||
'use strict';
|
||||
|
||||
// ── Constants ──────────────────────────────────────────────────────────────
|
||||
@@ -223,8 +223,8 @@ const NatusWheel = (() => {
|
||||
if (_staticBase) return _staticBase;
|
||||
const scripts = document.querySelectorAll('script[src]');
|
||||
for (const s of scripts) {
|
||||
if (s.src.includes('natus-wheel')) {
|
||||
_staticBase = s.src.replace(/natus-wheel\.js.*$/, '');
|
||||
if (s.src.includes('sky-wheel')) {
|
||||
_staticBase = s.src.replace(/sky-wheel\.js.*$/, '');
|
||||
return _staticBase;
|
||||
}
|
||||
}
|
||||
@@ -957,7 +957,7 @@ const NatusWheel = (() => {
|
||||
* Called on every draw() so a fresh innerHTML replaces any stale state.
|
||||
*/
|
||||
function _injectTooltipControls() {
|
||||
_tooltipEl = document.getElementById('id_natus_tooltip');
|
||||
_tooltipEl = document.getElementById('id_sky_tooltip');
|
||||
if (!_tooltipEl) return;
|
||||
_tooltipEl.innerHTML =
|
||||
`<button type="button" class="btn btn-equip nw-asp-don">DON</button>` +
|
||||
@@ -1384,8 +1384,8 @@ const NatusWheel = (() => {
|
||||
(() => {
|
||||
const scripts = document.querySelectorAll('script[src]');
|
||||
for (const s of scripts) {
|
||||
if (s.src.includes('natus-wheel')) {
|
||||
return s.src.replace(/natus-wheel\.js.*$/, 'icons/zodiac-signs/');
|
||||
if (s.src.includes('sky-wheel')) {
|
||||
return s.src.replace(/sky-wheel\.js.*$/, 'icons/zodiac-signs/');
|
||||
}
|
||||
}
|
||||
return '/static/apps/gameboard/icons/zodiac-signs/';
|
||||
@@ -1394,7 +1394,7 @@ const NatusWheel = (() => {
|
||||
await Promise.all(SIGNS.map(async sign => {
|
||||
const url = base + sign.name.toLowerCase() + '.svg';
|
||||
const resp = await window.fetch(url);
|
||||
if (!resp.ok) { console.warn(`NatusWheel: failed to load ${url}`); return; }
|
||||
if (!resp.ok) { console.warn(`SkyWheel: failed to load ${url}`); return; }
|
||||
const text = await resp.text();
|
||||
const doc = new DOMParser().parseFromString(text, 'image/svg+xml');
|
||||
const path = doc.querySelector('path');
|
||||
Reference in New Issue
Block a user