diff --git a/config.json b/config.json index 9a73073..2086fef 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "id": "events", - "version": "1.3.0-aio.6", + "version": "1.3.0-aio.5", "name": "Events", "repo": "https://git.atitlan.io/aiolabs/events", "short_description": "Sell and register event tickets", diff --git a/migrations.py b/migrations.py index 6f8e838..016ded1 100644 --- a/migrations.py +++ b/migrations.py @@ -162,16 +162,96 @@ 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. """ - # Add canceled and 'extra' columns to events table - await db.execute( - "ALTER TABLE events.events ADD COLUMN canceled BOOLEAN NOT NULL DEFAULT FALSE;" + await _alter_add_column_safe( + db, + "ALTER TABLE events.events ADD COLUMN canceled BOOLEAN NOT NULL DEFAULT FALSE", ) - await db.execute("ALTER TABLE events.events ADD COLUMN extra TEXT;") + 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") - # Add 'extra' column to ticket table - await db.execute("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 + ) + """) + await db.execute( + "INSERT INTO events.settings (id, auto_approve) " + "SELECT 1, FALSE WHERE NOT EXISTS " + "(SELECT 1 FROM events.settings WHERE id = 1)" + ) + + +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" + ) diff --git a/migrations_fork.py b/migrations_fork.py deleted file mode 100644 index 365d259..0000000 --- a/migrations_fork.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -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" - )