diff --git a/migrations.py b/migrations.py index 016ded1..6f8e838 100644 --- a/migrations.py +++ b/migrations.py @@ -162,96 +162,16 @@ async def m005_add_image_banner(db): await db.execute("ALTER TABLE events.events ADD COLUMN banner TEXT;") -async def _alter_add_column_safe(db, sql: str) -> None: - """ALTER TABLE ADD COLUMN that swallows duplicate-column errors. - - Earlier aiolabs/events forks added some of these columns under different - migration names (e.g. our former m007). Skipping the error keeps the - migration log monotonic for both fresh installs and pre-rebase upgrades. - """ - try: - await db.execute(sql) - except Exception as exc: - msg = str(exc).lower() - if "duplicate column" in msg or "already exists" in msg: - return - raise - - async def m006_add_extra_fields(db): """ Add a canceled and 'extra' column to events and ticket tables to support promo codes and ticket metadata. """ - await _alter_add_column_safe( - db, - "ALTER TABLE events.events ADD COLUMN canceled BOOLEAN NOT NULL DEFAULT FALSE", - ) - await _alter_add_column_safe(db, "ALTER TABLE events.events ADD COLUMN extra TEXT") - await _alter_add_column_safe(db, "ALTER TABLE events.ticket ADD COLUMN extra TEXT") - - -async def m007_add_user_id_support(db): - """ - Add user_id column to ticket table so a ticket can reference an LNbits - user id instead of (name, email). Application logic enforces that exactly - one identifier scheme is used per ticket. - """ - await _alter_add_column_safe( - db, "ALTER TABLE events.ticket ADD COLUMN user_id TEXT" - ) - - -async def m008_add_event_status(db): - """ - Add status column to events table for the proposal/approval workflow. - Values: 'proposed', 'approved', 'rejected'. Existing rows default to - 'approved' so they stay visible after upgrade. - """ - await _alter_add_column_safe( - db, - "ALTER TABLE events.events ADD COLUMN status TEXT NOT NULL DEFAULT 'approved'", - ) - - -async def m009_add_nostr_columns(db): - """ - Track the most recent NIP-52 calendar event we published for this event - (used for replaceable updates and NIP-09 deletes). - """ - await _alter_add_column_safe( - db, "ALTER TABLE events.events ADD COLUMN nostr_event_id TEXT" - ) - await _alter_add_column_safe( - db, "ALTER TABLE events.events ADD COLUMN nostr_event_created_at INTEGER" - ) - - -async def m010_add_events_settings(db): - """ - Create the extension settings singleton row used by the admin UI to - toggle e.g. auto_approve. - """ - await db.execute(""" - CREATE TABLE IF NOT EXISTS events.settings ( - id INTEGER PRIMARY KEY DEFAULT 1, - auto_approve BOOLEAN NOT NULL DEFAULT FALSE - ) - """) + # Add canceled and 'extra' columns to events table await db.execute( - "INSERT INTO events.settings (id, auto_approve) " - "SELECT 1, FALSE WHERE NOT EXISTS " - "(SELECT 1 FROM events.settings WHERE id = 1)" + "ALTER TABLE events.events ADD COLUMN canceled BOOLEAN NOT NULL DEFAULT FALSE;" ) + await db.execute("ALTER TABLE events.events ADD COLUMN extra TEXT;") - -async def m011_add_location_and_categories(db): - """ - Add NIP-52 calendar metadata (location and a JSON-encoded category list). - """ - await _alter_add_column_safe( - db, "ALTER TABLE events.events ADD COLUMN location TEXT" - ) - await _alter_add_column_safe( - db, "ALTER TABLE events.events ADD COLUMN categories TEXT" - ) + # Add 'extra' column to ticket table + await db.execute("ALTER TABLE events.ticket ADD COLUMN extra TEXT;") diff --git a/migrations_fork.py b/migrations_fork.py new file mode 100644 index 0000000..365d259 --- /dev/null +++ b/migrations_fork.py @@ -0,0 +1,105 @@ +""" +Fork-specific database migrations for the aiolabs events extension. + +These migrations are tracked separately under `events_fork` in the +`dbversions` table (loaded by `lnbits/core/helpers.py:migrate_extension_database`), +so they do not collide with upstream's `m{NNN}_*` numbering in +`migrations.py`. Keeping the upstream-tracked file untouched means +`git pull upstream` stays rebase-clean for schema changes. + +Conventions: + - Sequential numbering starting from m001. + - Each migration is `async def m{NNN}_(db)`. + - DDL must be idempotent: a fresh install runs every migration; an + install that previously ran the OLD versions of these as + `m007-m011` in `migrations.py` has the columns/tables already. + Use `_alter_add_column_safe` / `_create_table_safe` so re-runs are + no-ops instead of crashes. + +History compressed into m001 (was m007-m011 in migrations.py pre-v1.6 +rebase): + - m007 add_user_id_support (ticket.user_id column) + - m008 add_event_status (events.status column) + - m009 add_nostr_columns (events.nostr_event_id + created_at) + - m010 add_events_settings (events.settings singleton table) + - m011 add_location_and_categories (events.location + categories) +""" + + +async def _alter_add_column_safe(db, sql: str) -> None: + """ALTER TABLE ADD COLUMN that swallows duplicate-column errors. + + Re-running the squashed migration on a database that already has + these columns (from the pre-squash `m007-m011` in migrations.py) + must be a silent no-op. Same swallow we used in the old migrations. + """ + try: + await db.execute(sql) + except Exception as exc: + msg = str(exc).lower() + if "duplicate column" in msg or "already exists" in msg: + return + raise + + +async def m001_aio_event_schema(db): + """ + Apply every aiolabs schema delta on top of upstream events v1.3.0. + + This is the squashed equivalent of the pre-v1.6 sequence + m007 → m011. Order matters for the settings table seed insert + but the individual column adds are independent and idempotent. + """ + + # --- ticket.user_id ---------------------------------------------- + # Lets a ticket reference an LNbits user id instead of (name, email). + # Application logic enforces that exactly one identifier scheme is + # used per ticket. + await _alter_add_column_safe( + db, "ALTER TABLE events.ticket ADD COLUMN user_id TEXT" + ) + + # --- events.status ----------------------------------------------- + # Proposal / approval workflow. Existing rows default to 'approved' + # so they stay visible after upgrade. + await _alter_add_column_safe( + db, + "ALTER TABLE events.events ADD COLUMN status TEXT NOT NULL DEFAULT 'approved'", + ) + + # --- events.nostr_event_id, nostr_event_created_at --------------- + # Track the most recent NIP-52 calendar event we published, so + # subsequent edits can issue replaceable updates and NIP-09 deletes + # against the right addressable coordinate. + await _alter_add_column_safe( + db, "ALTER TABLE events.events ADD COLUMN nostr_event_id TEXT" + ) + await _alter_add_column_safe( + db, "ALTER TABLE events.events ADD COLUMN nostr_event_created_at INTEGER" + ) + + # --- events.settings --------------------------------------------- + # Singleton settings row used by the admin UI to toggle e.g. + # auto_approve. CREATE TABLE IF NOT EXISTS + a guarded seed keeps + # this idempotent. + await db.execute(""" + CREATE TABLE IF NOT EXISTS events.settings ( + id INTEGER PRIMARY KEY DEFAULT 1, + auto_approve BOOLEAN NOT NULL DEFAULT FALSE + ) + """) + await db.execute( + "INSERT INTO events.settings (id, auto_approve) " + "SELECT 1, FALSE WHERE NOT EXISTS " + "(SELECT 1 FROM events.settings WHERE id = 1)" + ) + + # --- events.location, events.categories -------------------------- + # NIP-52 calendar metadata. `categories` carries a JSON-encoded + # list of hashtags (the NIP-52 `t` tags). + await _alter_add_column_safe( + db, "ALTER TABLE events.events ADD COLUMN location TEXT" + ) + await _alter_add_column_safe( + db, "ALTER TABLE events.events ADD COLUMN categories TEXT" + )