From 8b0ad545c935cb9c775562f5417f3df7dd6955a9 Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Fri, 1 May 2026 02:22:43 -0400 Subject: [PATCH] =?UTF-8?q?collapse=20epic=20migrations=200007=E2=80=93002?= =?UTF-8?q?2=20=E2=86=92=200007=5Ffinalize=5Fearthman=5Fdeck;=20add=20rese?= =?UTF-8?q?t=5Fstaging=5Fdb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 16 incremental Earthman tweak migrations folded into one end-state finalize migration (rename mechanisms→energies / articulations→operations / reversal→reversal_qualifier; +italic_word; suit court reversals; Schizo energies+operations; card 49 polarity reversal titles; Castanedan Virtues trumps 6–9 + 19–21; trump 8 U+2011 hyphen; trump 9 U+00A0 nbsp; pips → MINOR) - 22 epic migrations → 7; 748 ITs green - new mgmt cmd `reset_staging_db` — drops schema (Postgres) / tables (sqlite) & re-runs migrate; refuses on prod hosts; needs `--i-mean-it` when DEBUG=False; interactive host-name confirmation locally; calls ensure_superuser after Code architected by Disco DeDisco Git commit message Co-Authored-By: Claude Opus 4.7 (1M context) --- src/apps/epic/management/__init__.py | 0 src/apps/epic/management/commands/__init__.py | 0 .../management/commands/reset_staging_db.py | 110 ++++++++++ .../migrations/0007_finalize_earthman_deck.py | 200 ++++++++++++++++++ .../0007_populate_middle_arcana_reversals.py | 73 ------- ..._rename_energies_operations_seed_schizo.py | 57 ----- .../migrations/0009_schizo_card_ref_spans.py | 53 ----- .../0010_major_arcana_hand_dots_icon.py | 49 ----- .../migrations/0011_nomad_schizo_icons.py | 43 ---- .../migrations/0012_delete_stray_pentacles.py | 27 --- .../epic/migrations/0013_fix_nomad_icon.py | 25 --- ...4_rename_reversal_to_reversal_qualifier.py | 22 -- .../0015_card49_polarity_reversal_titles.py | 60 ------ .../migrations/0016_card49_bestowing_eagle.py | 37 ---- .../migrations/0017_castanedan_virtues.py | 114 ---------- .../epic/migrations/0018_add_italic_word.py | 18 -- .../0019_explicit_virtues_italic_word.py | 51 ----- .../epic/migrations/0020_self_unimportance.py | 41 ---- src/apps/epic/migrations/0021_trump9_nbsp.py | 61 ------ .../migrations/0022_pips_to_minor_arcana.py | 42 ---- 20 files changed, 310 insertions(+), 773 deletions(-) create mode 100644 src/apps/epic/management/__init__.py create mode 100644 src/apps/epic/management/commands/__init__.py create mode 100644 src/apps/epic/management/commands/reset_staging_db.py create mode 100644 src/apps/epic/migrations/0007_finalize_earthman_deck.py delete mode 100644 src/apps/epic/migrations/0007_populate_middle_arcana_reversals.py delete mode 100644 src/apps/epic/migrations/0008_rename_energies_operations_seed_schizo.py delete mode 100644 src/apps/epic/migrations/0009_schizo_card_ref_spans.py delete mode 100644 src/apps/epic/migrations/0010_major_arcana_hand_dots_icon.py delete mode 100644 src/apps/epic/migrations/0011_nomad_schizo_icons.py delete mode 100644 src/apps/epic/migrations/0012_delete_stray_pentacles.py delete mode 100644 src/apps/epic/migrations/0013_fix_nomad_icon.py delete mode 100644 src/apps/epic/migrations/0014_rename_reversal_to_reversal_qualifier.py delete mode 100644 src/apps/epic/migrations/0015_card49_polarity_reversal_titles.py delete mode 100644 src/apps/epic/migrations/0016_card49_bestowing_eagle.py delete mode 100644 src/apps/epic/migrations/0017_castanedan_virtues.py delete mode 100644 src/apps/epic/migrations/0018_add_italic_word.py delete mode 100644 src/apps/epic/migrations/0019_explicit_virtues_italic_word.py delete mode 100644 src/apps/epic/migrations/0020_self_unimportance.py delete mode 100644 src/apps/epic/migrations/0021_trump9_nbsp.py delete mode 100644 src/apps/epic/migrations/0022_pips_to_minor_arcana.py diff --git a/src/apps/epic/management/__init__.py b/src/apps/epic/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/epic/management/commands/__init__.py b/src/apps/epic/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/epic/management/commands/reset_staging_db.py b/src/apps/epic/management/commands/reset_staging_db.py new file mode 100644 index 0000000..c8702c5 --- /dev/null +++ b/src/apps/epic/management/commands/reset_staging_db.py @@ -0,0 +1,110 @@ +"""Wipe the configured database and re-run all migrations from scratch. + +Intended for ephemeral environments (staging) where losing every user, room, +billpost, token, etc. is acceptable. Refuses to run when DEBUG=False unless +the operator explicitly confirms with --i-mean-it, and always prints the +DB host before doing anything destructive. + +Typical staging usage from the deploy host: + + docker exec -it gamearray python manage.py reset_staging_db --i-mean-it + +Locally (sqlite, DEBUG=True) the safety prompt is skipped: + + python src/manage.py reset_staging_db +""" +from django.conf import settings +from django.core.management import call_command +from django.core.management.base import BaseCommand, CommandError +from django.db import connection + + +PROD_HOST_FRAGMENTS = ("earthmanrpg.me",) + + +class Command(BaseCommand): + help = "Drop every table in the default DB and re-run migrations. Destructive." + + def add_arguments(self, parser): + parser.add_argument( + "--i-mean-it", + action="store_true", + help="Required when DEBUG=False. Bypasses the interactive confirmation.", + ) + parser.add_argument( + "--no-superuser", + action="store_true", + help="Skip the post-migrate ensure_superuser call.", + ) + + def handle(self, *args, **opts): + db_settings = settings.DATABASES["default"] + engine = db_settings.get("ENGINE", "") + host = db_settings.get("HOST") or db_settings.get("NAME") or "(unknown)" + + # Refuse outright if the host name suggests production + if any(frag in str(host) for frag in PROD_HOST_FRAGMENTS) and not host.startswith("staging"): + if "staging" not in str(host): + raise CommandError( + f"Refusing to reset DB at host={host!r} — looks like production. " + "Edit PROD_HOST_FRAGMENTS in this command if you really mean it." + ) + + self.stdout.write(self.style.WARNING( + f"\nAbout to wipe DB:\n ENGINE: {engine}\n HOST/NAME: {host}\n" + )) + + if not settings.DEBUG and not opts["i_mean_it"]: + raise CommandError( + "DEBUG=False — pass --i-mean-it to confirm. " + "(This is the staging-safety check; it does not bypass the prod-host refusal above.)" + ) + + if settings.DEBUG and not opts["i_mean_it"]: + answer = input("Type the DB host/name to confirm: ").strip() + if answer != str(host): + raise CommandError(f"Got {answer!r}, expected {str(host)!r}. Aborting.") + + # Drop schema. Postgres + sqlite both honor `flush --no-input`'s + # truncate-tables-in-place model, but for a *fresh* migration run we + # need the migration history wiped too. For Postgres the cleanest + # route is `DROP SCHEMA public CASCADE; CREATE SCHEMA public;` — + # for sqlite, deleting the file is simpler but Django's connection + # has it open. So: introspect the connection and drop all tables. + self.stdout.write("Dropping all tables…") + self._drop_all_tables() + + self.stdout.write("Running migrate from scratch…") + call_command("migrate", verbosity=1, interactive=False) + + if not opts["no_superuser"]: + try: + call_command("ensure_superuser", verbosity=1) + except Exception as exc: # pragma: no cover - depends on env vars + self.stdout.write(self.style.WARNING( + f"ensure_superuser skipped/failed: {exc}" + )) + + self.stdout.write(self.style.SUCCESS("\nDB reset complete.")) + + def _drop_all_tables(self): + vendor = connection.vendor + with connection.cursor() as cursor: + if vendor == "postgresql": + cursor.execute("DROP SCHEMA public CASCADE;") + cursor.execute("CREATE SCHEMA public;") + cursor.execute("GRANT ALL ON SCHEMA public TO public;") + elif vendor == "sqlite": + cursor.execute("PRAGMA foreign_keys = OFF;") + cursor.execute( + "SELECT name FROM sqlite_master " + "WHERE type='table' AND name NOT LIKE 'sqlite_%'" + ) + tables = [row[0] for row in cursor.fetchall()] + for table in tables: + cursor.execute(f'DROP TABLE IF EXISTS "{table}"') + cursor.execute("PRAGMA foreign_keys = ON;") + else: + raise CommandError( + f"reset_staging_db only knows postgresql + sqlite, got {vendor!r}" + ) diff --git a/src/apps/epic/migrations/0007_finalize_earthman_deck.py b/src/apps/epic/migrations/0007_finalize_earthman_deck.py new file mode 100644 index 0000000..0615876 --- /dev/null +++ b/src/apps/epic/migrations/0007_finalize_earthman_deck.py @@ -0,0 +1,200 @@ +"""Collapse of old migrations 0007–0022 into a single end-state finalize. + +Schema: + - mechanisms → energies (was 0008) + - articulations → operations (was 0008) + - reversal → reversal_qualifier (was 0014) + - +italic_word (was 0018) + +Data (operates on the Earthman deck seeded in 0004; idempotent against the +current schema, which is the post-rename state thanks to the operations +above running first): + - Middle court reversal_qualifier per suit (was 0007) + - Schizo energies + operations w/ .card-ref (was 0008 + 0009) + - fa-hand-dots fallback for empty MAJOR icons (was 0010; only card 41 + in fresh-seed state) + - Card 49 polarity-split reversal titles (was 0015 + 0016) + - Castanedan Virtues: trumps 6-9 + 19-21 (was 0017) + - italic_word for trumps 19-21 (was 0019) + - Trump 8 rename + non-breaking hyphen (was 0020 + 0021) + - Trump 9 non-breaking space (was 0021) + - Pip cards (number 1-10) MIDDLE → MINOR arcana (was 0022) + +Skipped (all no-ops against fresh 0004 seed): + - 0011 (nomad/schizo icons already correct in 0004) + - 0012 (no PENTACLES seeded for Earthman in 0004) + - 0013 (nomad icon already fa-hat-cowboy-side in 0004) +""" +from django.db import migrations, models + + +# ── Schizo energies + operations ───────────────────────────────────────────── +CR = '{}' + +SCHIZO_ENERGIES = [ + {"type": "LIBIDO", "effect": f'When encountering territorial Libido, may convert Emanation into {CR.format("1. The Priest")}.'}, + {"type": "NUMEN", "effect": f'When encountering despotic Numen, may convert Emanation into {CR.format("1. The Powerful")}.'}, + {"type": "VOLUPTAS", "effect": f'When encountering axiomatic Voluptas, may convert Emanation into {CR.format("1. The Normal")}.'}, + {"type": "VOLUPTAS", "effect": f'When encountering annihilating Voluptas, may convert Emanation into {CR.format("1. The Surrendered")}.'}, +] + +SCHIZO_OPERATIONS = [ + {"type": "COVER", "effect": f'When covering {CR.format("2. The Occultist")} she may choose, by converting her own Reversal into {CR.format("2. Pestilence")}, to convert this Reversal into {CR.format("1. The Pervert")}.'}, + {"type": "CROWN", "effect": f'When crowning {CR.format("3. The Despot")} she may choose, by converting her own Reversal into {CR.format("3. War")}, to convert this Reversal into {CR.format("1. The Paranoiac")}.'}, + {"type": "BEHIND", "effect": f'When behind {CR.format("4. The Capitalist")} he may choose, by converting his own Reversal into {CR.format("4. Famine")}, to convert this Reversal into {CR.format("1. The Neurotic")}.'}, + {"type": "BEFORE", "effect": f'When before {CR.format("5. The Fascist")} he may choose, by converting his own Reversal into {CR.format("5. Death")}, to convert this Reversal into {CR.format("1. The Suicidal")}.'}, +] + +# ── Middle court suit reversals ────────────────────────────────────────────── +SUIT_REVERSAL_QUALIFIER = { + "BRANDS": "Seething", + "GRAILS": "Gloomy", + "BLADES": "Nervous", + "CROWNS": "Vacant", +} +COURT_NUMBERS = [11, 12, 13, 14] + +# ── Castanedan Virtues ─────────────────────────────────────────────────────── +IMPLICIT_VIRTUES = [ + # (number, levity_qualifier, gravity_qualifier, reversal_title) + (6, "Sublimating", "Sedimentary", "Indulged Folly"), + (7, "Sublimating", "Sedimentary", "Indulgent Doing"), + (8, "Sublimating", "Sedimentary", "Self-Indulgence"), + (9, "Sublimating", "Sedimentary", "Indulging Personal History"), +] + +EXPLICIT_VIRTUES = [ + # (number, levity_emanation, gravity_emanation, levity_reversal, gravity_reversal, italic_word) + (19, "The Hunter's Stalking", "The Hunter's Stalking", "The Sleeper's Stalking", "The Quarry's Stalking", "Stalking"), + (20, "The Dreamer's Dreaming", "The Dreamer's Dreaming", "The Sleeper's Dreaming", "The Dreamed's Dreaming", "Dreaming"), + (21, "The Warrior's Intent", "The Warrior's Intent", "The Sleeper's Intent", "The Predator's Intent", "Intent"), +] + + +def finalize(apps, schema_editor): + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + + # Middle court suit reversals + for suit, qualifier in SUIT_REVERSAL_QUALIFIER.items(): + TarotCard.objects.filter( + deck_variant=earthman, arcana="MIDDLE", suit=suit, + number__in=COURT_NUMBERS, + ).update(reversal_qualifier=qualifier) + + # Schizo: clear stray reversal_qualifier (0004 seeds 'Territoriality') + + # populate energies/operations + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=1, + ).update( + reversal_qualifier="", + energies=SCHIZO_ENERGIES, + operations=SCHIZO_OPERATIONS, + ) + + # fa-hand-dots fallback for empty MAJOR icons (number ≥ 2) + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number__gte=2, icon="", + ).update(icon="fa-hand-dots") + + # Card 49 polarity reversal titles + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=49, + ).update( + levity_reversal="The Vibrational Mould of Man", + gravity_reversal="The Bestowing Eagle", + ) + + # Castanedan Virtues — implicit (trumps 6-9): trump 7 name canonicalize + + # qualifiers + reversal titles + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=7, + ).update(name="Not-Doing") + for number, lvty, grav, rev in IMPLICIT_VIRTUES: + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=number, + ).update( + levity_qualifier=lvty, + gravity_qualifier=grav, + levity_reversal=rev, + gravity_reversal=rev, + ) + + # Castanedan Virtues — explicit (trumps 19-21): polarity-split titles + + # italic_word for the agency stem + for number, le, ge, lr, gr, word in EXPLICIT_VIRTUES: + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=number, + ).update( + levity_emanation=le, + gravity_emanation=ge, + levity_reversal=lr, + gravity_reversal=gr, + italic_word=word, + ) + + # Trump 8: "Losing Self-Importance" → "Self‑Unimportance" w/ U+2011 + # non-breaking hyphen (keeps title on one line above qualifier) + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=8, + ).update(name="Self‑Unimportance", slug="self-unimportance") + + # Trump 9: insert U+00A0 between "Personal" and "History" so they wrap as + # a single unit ("Erasing / Personal History, / Sublimating") + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=9, + ).update(name="Erasing Personal History") + + # Pip cards (number 1-10) → MINOR arcana; courts (11-14) stay MIDDLE + TarotCard.objects.filter( + deck_variant=earthman, arcana="MIDDLE", number__lte=10, + ).update(arcana="MINOR") + + +def revert(apps, schema_editor): + """Reverse just enough to restore 0006 schema state. Data reverts to the + raw 0004 seed shape (without any of the post-seed tweaks).""" + TarotCard = apps.get_model("epic", "TarotCard") + DeckVariant = apps.get_model("epic", "DeckVariant") + try: + earthman = DeckVariant.objects.get(slug="earthman") + except DeckVariant.DoesNotExist: + return + # Pip arcana + TarotCard.objects.filter( + deck_variant=earthman, arcana="MINOR", number__lte=10, + ).update(arcana="MIDDLE") + # Trump 8 + 9 names back + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=8, + ).update(name="Losing Self-Importance", slug="losing-self-importance") + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=9, + ).update(name="Erasing Personal History") + # Trump 7 name back + TarotCard.objects.filter( + deck_variant=earthman, arcana="MAJOR", number=7, + ).update(name="Not Doing") + + +class Migration(migrations.Migration): + + dependencies = [ + ("epic", "0006_add_deck_variant_to_tableseat"), + ] + + operations = [ + migrations.RenameField("TarotCard", "mechanisms", "energies"), + migrations.RenameField("TarotCard", "articulations", "operations"), + migrations.RenameField("TarotCard", "reversal", "reversal_qualifier"), + migrations.AddField( + model_name="tarotcard", + name="italic_word", + field=models.CharField(blank=True, default="", max_length=50), + ), + migrations.RunPython(finalize, reverse_code=revert), + ] diff --git a/src/apps/epic/migrations/0007_populate_middle_arcana_reversals.py b/src/apps/epic/migrations/0007_populate_middle_arcana_reversals.py deleted file mode 100644 index 26a3d26..0000000 --- a/src/apps/epic/migrations/0007_populate_middle_arcana_reversals.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Populate TarotCard.reversal for Earthman Middle Arcana court cards. - -Each suit has a fixed reversal qualifier that replaces the polarity qualifier -(Elevated/Graven) when the card is spun to its reversed face: - Brands → Seething Grails → Gloomy Blades → Nervous Crowns → Vacant - -Also clears the incorrectly inherited reversal on The Schizo (card 1), which -mistakenly carried 'Territoriality' from The Occultist (card 2). -""" -from django.db import migrations - -SUIT_REVERSAL_QUALIFIER = { - "BRANDS": "Seething", - "GRAILS": "Gloomy", - "BLADES": "Nervous", - "CROWNS": "Vacant", -} - -RANK_NAMES = {11: "Maid", 12: "Jack", 13: "Queen", 14: "King"} - - -def populate_reversals(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - - # Middle Arcana court cards - for suit, qualifier in SUIT_REVERSAL_QUALIFIER.items(): - TarotCard.objects.filter( - deck_variant=earthman, - arcana="MIDDLE", - suit=suit, - number__in=list(RANK_NAMES.keys()), - ).update(reversal=qualifier) - - # Clear The Schizo's incorrectly inherited reversal (belongs to The Occultist) - TarotCard.objects.filter( - deck_variant=earthman, - arcana="MAJOR", - number=1, - ).update(reversal="") - - -def clear_reversals(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MIDDLE", - suit__in=list(SUIT_REVERSAL_QUALIFIER.keys()), - number__in=list(RANK_NAMES.keys()), - ).update(reversal="") - TarotCard.objects.filter(deck_variant=earthman, arcana="MAJOR", number=1).update( - reversal="Territoriality" - ) - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0006_add_deck_variant_to_tableseat"), - ] - - operations = [ - migrations.RunPython(populate_reversals, reverse_code=clear_reversals), - ] diff --git a/src/apps/epic/migrations/0008_rename_energies_operations_seed_schizo.py b/src/apps/epic/migrations/0008_rename_energies_operations_seed_schizo.py deleted file mode 100644 index db8ff8c..0000000 --- a/src/apps/epic/migrations/0008_rename_energies_operations_seed_schizo.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Rename mechanisms→energies and articulations→operations on TarotCard; -seed The Schizo (Earthman major arcana card 1) with Energy and Operation entries. -""" -from django.db import migrations - -CR = '{}' - -SCHIZO_ENERGIES = [ - {"type": "LIBIDO", "effect": f'When encountering territorial Libido, may convert Emanation into {CR.format("1. The Priest")}.'}, - {"type": "NUMEN", "effect": f'When encountering despotic Numen, may convert Emanation into {CR.format("1. The Powerful")}.'}, - {"type": "VOLUPTAS", "effect": f'When encountering axiomatic Voluptas, may convert Emanation into {CR.format("1. The Normal")}.'}, - {"type": "VOLUPTAS", "effect": f'When encountering annihilating Voluptas, may convert Emanation into {CR.format("1. The Surrendered")}.'}, -] - -SCHIZO_OPERATIONS = [ - {"type": "COVER", "effect": f'When covering {CR.format("2. The Occultist")} she may choose, by converting her own Reversal into {CR.format("2. Pestilence")}, to convert this Reversal into {CR.format("1. The Pervert")}.'}, - {"type": "CROWN", "effect": f'When crowning {CR.format("3. The Despot")} she may choose, by converting her own Reversal into {CR.format("3. War")}, to convert this Reversal into {CR.format("1. The Paranoiac")}.'}, - {"type": "BEHIND", "effect": f'When behind {CR.format("4. The Capitalist")} he may choose, by converting his own Reversal into {CR.format("4. Famine")}, to convert this Reversal into {CR.format("1. The Neurotic")}.'}, - {"type": "BEFORE", "effect": f'When before {CR.format("5. The Fascist")} he may choose, by converting his own Reversal into {CR.format("5. Death")}, to convert this Reversal into {CR.format("1. The Suicidal")}.'}, -] - - -def seed_schizo(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=1, - ).update(energies=SCHIZO_ENERGIES, operations=SCHIZO_OPERATIONS) - - -def clear_schizo(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=1, - ).update(energies=[], operations=[]) - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0007_populate_middle_arcana_reversals"), - ] - - operations = [ - migrations.RenameField("TarotCard", "mechanisms", "energies"), - migrations.RenameField("TarotCard", "articulations", "operations"), - migrations.RunPython(seed_schizo, reverse_code=clear_schizo), - ] diff --git a/src/apps/epic/migrations/0009_schizo_card_ref_spans.py b/src/apps/epic/migrations/0009_schizo_card_ref_spans.py deleted file mode 100644 index 5889562..0000000 --- a/src/apps/epic/migrations/0009_schizo_card_ref_spans.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Re-seed The Schizo's energies and operations with .card-ref HTML spans.""" -from django.db import migrations - -CR = '{}' - -SCHIZO_ENERGIES = [ - {"type": "LIBIDO", "effect": f'When encountering territorial Libido, may convert Emanation into {CR.format("1. The Priest")}.'}, - {"type": "NUMEN", "effect": f'When encountering despotic Numen, may convert Emanation into {CR.format("1. The Powerful")}.'}, - {"type": "VOLUPTAS", "effect": f'When encountering axiomatic Voluptas, may convert Emanation into {CR.format("1. The Normal")}.'}, - {"type": "VOLUPTAS", "effect": f'When encountering annihilating Voluptas, may convert Emanation into {CR.format("1. The Surrendered")}.'}, -] - -SCHIZO_OPERATIONS = [ - {"type": "COVER", "effect": f'When covering {CR.format("2. The Occultist")} she may choose, by converting her own Reversal into {CR.format("2. Pestilence")}, to convert this Reversal into {CR.format("1. The Pervert")}.'}, - {"type": "CROWN", "effect": f'When crowning {CR.format("3. The Despot")} she may choose, by converting her own Reversal into {CR.format("3. War")}, to convert this Reversal into {CR.format("1. The Paranoiac")}.'}, - {"type": "BEHIND", "effect": f'When behind {CR.format("4. The Capitalist")} he may choose, by converting his own Reversal into {CR.format("4. Famine")}, to convert this Reversal into {CR.format("1. The Neurotic")}.'}, - {"type": "BEFORE", "effect": f'When before {CR.format("5. The Fascist")} he may choose, by converting his own Reversal into {CR.format("5. Death")}, to convert this Reversal into {CR.format("1. The Suicidal")}.'}, -] - - -def seed_schizo(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=1, - ).update(energies=SCHIZO_ENERGIES, operations=SCHIZO_OPERATIONS) - - -def clear_schizo(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=1, - ).update(energies=[], operations=[]) - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0008_rename_energies_operations_seed_schizo"), - ] - - operations = [ - migrations.RunPython(seed_schizo, reverse_code=clear_schizo), - ] diff --git a/src/apps/epic/migrations/0010_major_arcana_hand_dots_icon.py b/src/apps/epic/migrations/0010_major_arcana_hand_dots_icon.py deleted file mode 100644 index d7ee1dd..0000000 --- a/src/apps/epic/migrations/0010_major_arcana_hand_dots_icon.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Assign fa-hand-dots icon to all Earthman Major Arcana cards with number >= 2. - -Cards 0 (The Nomad) and 1 (The Schizo) keep their existing icon value so they -can receive distinct icons later. All other Major Arcana groups (Popes, Implicit -Virtues, Elements, Realms, Explicit Virtues, Zodiac, Lunars, Planets, Inner Rings, -polarity-split finals) default to fa-hand-dots until per-group icons are assigned. -""" -from django.db import migrations - - -def assign_hand_dots(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, - arcana="MAJOR", - number__gte=2, - icon="", - ).update(icon="fa-hand-dots") - - -def clear_hand_dots(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, - arcana="MAJOR", - number__gte=2, - icon="fa-hand-dots", - ).update(icon="") - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0009_schizo_card_ref_spans"), - ] - - operations = [ - migrations.RunPython(assign_hand_dots, reverse_code=clear_hand_dots), - ] diff --git a/src/apps/epic/migrations/0011_nomad_schizo_icons.py b/src/apps/epic/migrations/0011_nomad_schizo_icons.py deleted file mode 100644 index ef968cf..0000000 --- a/src/apps/epic/migrations/0011_nomad_schizo_icons.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Assign individual icons to The Nomad (0) and The Schizo (1). - -All other Major Arcana already have fa-hand-dots from migration 0010. -""" -from django.db import migrations - -ICONS = {0: 'fa-hat-cowboy-side', 1: 'fa-hat-wizard'} - - -def assign_icons(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - for number, icon in ICONS.items(): - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=number - ).update(icon=icon) - - -def clear_icons(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number__in=list(ICONS.keys()) - ).update(icon="") - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0010_major_arcana_hand_dots_icon"), - ] - - operations = [ - migrations.RunPython(assign_icons, reverse_code=clear_icons), - ] diff --git a/src/apps/epic/migrations/0012_delete_stray_pentacles.py b/src/apps/epic/migrations/0012_delete_stray_pentacles.py deleted file mode 100644 index 8e281c3..0000000 --- a/src/apps/epic/migrations/0012_delete_stray_pentacles.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Delete 4 stray PENTACLES court cards from the Earthman deck. - -These survived the migration collapse; the Earthman deck uses -BRANDS/GRAILS/BLADES/CROWNS only. -""" -from django.db import migrations - - -def delete_pentacles(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter(deck_variant=earthman, suit="PENTACLES").delete() - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0011_nomad_schizo_icons"), - ] - - operations = [ - migrations.RunPython(delete_pentacles, reverse_code=migrations.RunPython.noop), - ] diff --git a/src/apps/epic/migrations/0013_fix_nomad_icon.py b/src/apps/epic/migrations/0013_fix_nomad_icon.py deleted file mode 100644 index a327cd1..0000000 --- a/src/apps/epic/migrations/0013_fix_nomad_icon.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Fix The Nomad icon: fa-hat-cowboy → fa-hat-cowboy-side.""" -from django.db import migrations - - -def fix_nomad_icon(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=0, icon="fa-hat-cowboy" - ).update(icon="fa-hat-cowboy-side") - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0012_delete_stray_pentacles"), - ] - - operations = [ - migrations.RunPython(fix_nomad_icon, reverse_code=migrations.RunPython.noop), - ] diff --git a/src/apps/epic/migrations/0014_rename_reversal_to_reversal_qualifier.py b/src/apps/epic/migrations/0014_rename_reversal_to_reversal_qualifier.py deleted file mode 100644 index 2def261..0000000 --- a/src/apps/epic/migrations/0014_rename_reversal_to_reversal_qualifier.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Rename TarotCard.reversal → TarotCard.reversal_qualifier. - -Symmetric naming with levity_qualifier / gravity_qualifier; disambiguates the -qualifier-text field from the reversal *axis* state and the keywords_reversed -list. Pure column rename — no data movement. -""" -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0013_fix_nomad_icon"), - ] - - operations = [ - migrations.RenameField( - model_name="tarotcard", - old_name="reversal", - new_name="reversal_qualifier", - ), - ] diff --git a/src/apps/epic/migrations/0015_card49_polarity_reversal_titles.py b/src/apps/epic/migrations/0015_card49_polarity_reversal_titles.py deleted file mode 100644 index 0aff797..0000000 --- a/src/apps/epic/migrations/0015_card49_polarity_reversal_titles.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Populate card 49's polarity-split reversal titles. - -The Earthman deck's last two cards (48–49) carry distinct titles per polarity -(stored in `levity_emanation` / `gravity_emanation` / `levity_reversal` / -`gravity_reversal`) rather than a shared title + qualifier. - -Card 48 had its full set seeded in migration 0004: - levity: Father Sky → reversal: The Storm - gravity: Mother Sea → reversal: The Flood - -Card 49 had only emanations seeded; this migration fills the reversals: - levity: The Effulgent Mould of Man → reversal: The Vibrational Mould of Man - gravity: The Devouring Eagle → reversal: The All-Bestowing Eagle - -The "qualifier" (Effulgent / Vibrational / Devouring / All-Bestowing) is baked -into the title between "The" and the title-proper rather than rendered as a -separate qualifier slot — the per-polarity title strings are stored verbatim. -""" -from django.db import migrations - - -def populate_card49_reversals(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=49, - ).update( - levity_reversal="The Vibrational Mould of Man", - gravity_reversal="The All-Bestowing Eagle", - ) - - -def clear_card49_reversals(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=49, - ).update( - levity_reversal="", - gravity_reversal="", - ) - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0014_rename_reversal_to_reversal_qualifier"), - ] - - operations = [ - migrations.RunPython(populate_card49_reversals, reverse_code=clear_card49_reversals), - ] diff --git a/src/apps/epic/migrations/0016_card49_bestowing_eagle.py b/src/apps/epic/migrations/0016_card49_bestowing_eagle.py deleted file mode 100644 index 551618f..0000000 --- a/src/apps/epic/migrations/0016_card49_bestowing_eagle.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Tweak card 49 gravity_reversal: 'All-Bestowing Eagle' → 'Bestowing Eagle'.""" -from django.db import migrations - - -def forward(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=49, - ).update(gravity_reversal="The Bestowing Eagle") - - -def reverse(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=49, - ).update(gravity_reversal="The All-Bestowing Eagle") - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0015_card49_polarity_reversal_titles"), - ] - - operations = [ - migrations.RunPython(forward, reverse_code=reverse), - ] diff --git a/src/apps/epic/migrations/0017_castanedan_virtues.py b/src/apps/epic/migrations/0017_castanedan_virtues.py deleted file mode 100644 index d0df690..0000000 --- a/src/apps/epic/migrations/0017_castanedan_virtues.py +++ /dev/null @@ -1,114 +0,0 @@ -"""Populate the seven Castanedan Virtues — trumps 6–9 (Implicit) + 19–21 (Explicit). - -Implicit Virtues (6–9): emanation qualifier differs by polarity (Sublimating / -Sedimentary), name is shared. Reversal is a single full string shared across -both polarities (the agency word — Controlled / Not / Losing / Erasing — -flips to Indulged / Indulgent / Self-Indulgence / Indulging). We fill the -standard `levity_qualifier` / `gravity_qualifier` slots so the major-arcana -upright renders "Controlled Folly,\nSublimating" via the existing template -branch; we fill BOTH `levity_reversal` + `gravity_reversal` with the same -string so a FLIP'd reversal still picks up the override (an empty side falls -through to the default major-arcana rendering). - -Explicit Virtues (19–21): emanation is shared across polarities (e.g. "The -Hunter's Stalking" — no qualifier + stem decomposition), reversal differs by -polarity. All four polarity-split title fields filled. - -Also canonicalizes trump 7's name from "Not Doing" to "Not-Doing" per the spec -doc (slug "not-doing" already correct). -""" -from django.db import migrations - - -IMPLICIT = [ - # (number, levity_qualifier, gravity_qualifier, reversal_title) - (6, "Sublimating", "Sedimentary", "Indulged Folly"), - (7, "Sublimating", "Sedimentary", "Indulgent Doing"), - (8, "Sublimating", "Sedimentary", "Self-Indulgence"), - (9, "Sublimating", "Sedimentary", "Indulging Personal History"), -] - -EXPLICIT = [ - # (number, levity_emanation, gravity_emanation, levity_reversal, gravity_reversal) - (19, "The Hunter's Stalking", "The Hunter's Stalking", "The Sleeper's Stalking", "The Quarry's Stalking"), - (20, "The Dreamer's Dreaming", "The Dreamer's Dreaming", "The Sleeper's Dreaming", "The Dreamed's Dreaming"), - (21, "The Warrior's Intent", "The Warrior's Intent", "The Sleeper's Intent", "The Predator's Intent"), -] - - -def forward(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - - # Trump 7 name canonicalization - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=7, - ).update(name="Not-Doing") - - for number, lvty, grav, rev in IMPLICIT: - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=number, - ).update( - levity_qualifier=lvty, - gravity_qualifier=grav, - levity_reversal=rev, - gravity_reversal=rev, - ) - - for number, le, ge, lr, gr in EXPLICIT: - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=number, - ).update( - levity_emanation=le, - gravity_emanation=ge, - levity_reversal=lr, - gravity_reversal=gr, - ) - - -def reverse(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=7, - ).update(name="Not Doing") - - for number, _lvty, _grav, _rev in IMPLICIT: - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=number, - ).update( - levity_qualifier="", - gravity_qualifier="", - levity_reversal="", - gravity_reversal="", - ) - - for number, _le, _ge, _lr, _gr in EXPLICIT: - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=number, - ).update( - levity_emanation="", - gravity_emanation="", - levity_reversal="", - gravity_reversal="", - ) - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0016_card49_bestowing_eagle"), - ] - - operations = [ - migrations.RunPython(forward, reverse_code=reverse), - ] diff --git a/src/apps/epic/migrations/0018_add_italic_word.py b/src/apps/epic/migrations/0018_add_italic_word.py deleted file mode 100644 index ebb301c..0000000 --- a/src/apps/epic/migrations/0018_add_italic_word.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 6.0 on 2026-05-01 03:28 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('epic', '0017_castanedan_virtues'), - ] - - operations = [ - migrations.AddField( - model_name='tarotcard', - name='italic_word', - field=models.CharField(blank=True, default='', max_length=50), - ), - ] diff --git a/src/apps/epic/migrations/0019_explicit_virtues_italic_word.py b/src/apps/epic/migrations/0019_explicit_virtues_italic_word.py deleted file mode 100644 index 5727e90..0000000 --- a/src/apps/epic/migrations/0019_explicit_virtues_italic_word.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Set TarotCard.italic_word for trumps 19-21 (Stalking / Dreaming / Intent). - -Each of these three Castanedan virtues has its title key-word italicized -across every emanation/reversal slot ("The Hunter's *Stalking*", "The -Sleeper's *Stalking*", etc.). Storing the word in a single field lets the -renderer wrap it in at display time without HTML in the data. -""" -from django.db import migrations - - -WORDS = { - 19: "Stalking", - 20: "Dreaming", - 21: "Intent", -} - - -def forward(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - for number, word in WORDS.items(): - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=number, - ).update(italic_word=word) - - -def reverse(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number__in=list(WORDS), - ).update(italic_word="") - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0018_add_italic_word"), - ] - - operations = [ - migrations.RunPython(forward, reverse_code=reverse), - ] diff --git a/src/apps/epic/migrations/0020_self_unimportance.py b/src/apps/epic/migrations/0020_self_unimportance.py deleted file mode 100644 index 1e7b7fc..0000000 --- a/src/apps/epic/migrations/0020_self_unimportance.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Trump 8 rename: Losing Self-Importance → Self-Unimportance. - -The renamed form fits on one fan-card line above the Sublimating/Sedimentary -qualifier without a scaleX squeeze. -""" -from django.db import migrations - - -def forward(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=8, - ).update(name="Self-Unimportance", slug="self-unimportance") - - -def reverse(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=8, - ).update(name="Losing Self-Importance", slug="losing-self-importance") - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0019_explicit_virtues_italic_word"), - ] - - operations = [ - migrations.RunPython(forward, reverse_code=reverse), - ] diff --git a/src/apps/epic/migrations/0021_trump9_nbsp.py b/src/apps/epic/migrations/0021_trump9_nbsp.py deleted file mode 100644 index 14cec28..0000000 --- a/src/apps/epic/migrations/0021_trump9_nbsp.py +++ /dev/null @@ -1,61 +0,0 @@ -"""Long-title wrap fixes for trumps 8 and 9. - - Trump 8 "Self-Unimportance" → swap the hyphen for U+2011 (non-breaking - hyphen) so it stays glued and the title sits on one line above - Sublimating / Sedimentary. - - Trump 9 "Erasing Personal History" → insert U+00A0 (non-breaking space) - between "Personal" and "History" so the browser keeps them together, - forcing "Erasing" alone on line 1 and "Personal History," on line 2. -""" -from django.db import migrations - - -# Trump 8 -OLD_8 = "Self-Unimportance" -NEW_8 = "Self‑Unimportance" - -# Trump 9 -OLD_9 = "Erasing Personal History" -NEW_9 = "Erasing Personal History" - - -def forward(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=8, - ).update(name=NEW_8) - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=9, - ).update(name=NEW_9) - - -def reverse(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=8, - ).update(name=OLD_8) - TarotCard.objects.filter( - deck_variant=earthman, arcana="MAJOR", number=9, - ).update(name=OLD_9) - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0020_self_unimportance"), - ] - - operations = [ - migrations.RunPython(forward, reverse_code=reverse), - ] diff --git a/src/apps/epic/migrations/0022_pips_to_minor_arcana.py b/src/apps/epic/migrations/0022_pips_to_minor_arcana.py deleted file mode 100644 index fc2fe61..0000000 --- a/src/apps/epic/migrations/0022_pips_to_minor_arcana.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Reclassify Earthman pip cards (number 1-10) from MIDDLE to MINOR arcana. - -The 0004 reseed initially lumped pips + court cards under MIDDLE; pips -should be MINOR arcana, with MIDDLE reserved for the Earthman court -cards (Maid/Jack/Queen/King at numbers 11-14). -""" -from django.db import migrations - - -def forward(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MIDDLE", number__lte=10, - ).update(arcana="MINOR") - - -def reverse(apps, schema_editor): - TarotCard = apps.get_model("epic", "TarotCard") - DeckVariant = apps.get_model("epic", "DeckVariant") - try: - earthman = DeckVariant.objects.get(slug="earthman") - except DeckVariant.DoesNotExist: - return - TarotCard.objects.filter( - deck_variant=earthman, arcana="MINOR", number__lte=10, - ).update(arcana="MIDDLE") - - -class Migration(migrations.Migration): - - dependencies = [ - ("epic", "0021_trump9_nbsp"), - ] - - operations = [ - migrations.RunPython(forward, reverse_code=reverse), - ]