From 27cc8d2f1ce12a41d7299c288d446b9702b850df Mon Sep 17 00:00:00 2001 From: Padreug Date: Fri, 22 May 2026 09:24:35 +0200 Subject: [PATCH] chore: rebase onto upstream v1.6.1 + bump to v1.6.1-aio.1 Rebases the aio fork onto upstream v1.6.1 (4bf867e), pulling in: - fiat checkout + email/Nostr DM ticket notifications (PR #50) - currency-conversion fix (v1.5.0) - custom notification subject/body (v1.6.0) - resend-email button on the ticket list (PR #51) Notable merges: - views_api.api_event_update keeps the explicit-field-list gating from the aio.4 security fix, with allow_fiat + fiat_currency added so an owner editing a fiat-enabled event keeps the fiat config. - models.PublicEvent now exposes both upstream's fiat fields and our location / categories / status fields. - migrations.py reverts to byte-identical to upstream v1.6.1 (no aio entries); fork schema lives in migrations_fork.py (per aiolabs/lnbits#8). - Lint reformatted with black + ruff to match upstream style. Contributors entry adds `padreug` (aio fork maintainer). Co-Authored-By: Claude Opus 4.7 (1M context) --- __init__.py | 4 +--- config.json | 9 +++++++-- models.py | 4 +--- nostr/nostr_client.py | 15 ++++----------- nostr_publisher.py | 2 +- nostr_sync.py | 8 +++++--- views_api.py | 14 +++----------- 7 files changed, 22 insertions(+), 34 deletions(-) diff --git a/__init__.py b/__init__.py index c2f2300..b6b58a9 100644 --- a/__init__.py +++ b/__init__.py @@ -75,9 +75,7 @@ def events_start(): except Exception as exc: logger.error(f"[EVENTS] Nostr sync task failed: {exc}") - task3 = create_permanent_unique_task( - "ext_events_nostr_sync", _sync_nostr_events - ) + task3 = create_permanent_unique_task("ext_events_nostr_sync", _sync_nostr_events) scheduled_tasks.append(task3) diff --git a/config.json b/config.json index a945b43..57a7f75 100644 --- a/config.json +++ b/config.json @@ -1,8 +1,8 @@ { "id": "events", - "version": "1.6.1", + "version": "1.6.1-aio.1", "name": "Events", - "repo": "https://github.com/lnbits/events", + "repo": "https://git.atitlan.io/aiolabs/events", "short_description": "Sell and register event tickets", "description": "", "tile": "/events/static/image/events.png", @@ -32,6 +32,11 @@ "name": "motorina0", "uri": "https://github.com/motorina0", "role": "Developer" + }, + { + "name": "padreug", + "uri": "https://git.atitlan.io/padreug", + "role": "Developer (aio fork: approval workflow + NIP-52 Nostr sync + edit gating)" } ], "images": [ diff --git a/models.py b/models.py index 6b80537..d3f43d3 100644 --- a/models.py +++ b/models.py @@ -140,9 +140,7 @@ class CreateTicket(BaseModel): email = values.get("email") user_id = values.get("user_id") if not user_id and not (name and email): - raise ValueError( - "Either user_id or both name and email must be provided" - ) + raise ValueError("Either user_id or both name and email must be provided") if user_id and (name or email): raise ValueError("Cannot provide both user_id and name/email") return values diff --git a/nostr/nostr_client.py b/nostr/nostr_client.py index 8e0afc5..4de332f 100644 --- a/nostr/nostr_client.py +++ b/nostr/nostr_client.py @@ -39,8 +39,7 @@ class NostrClient: async def connect(self) -> WebSocketApp: relay_endpoint = encrypt_internal_message("relay", urlsafe=True) ws_url = ( - f"ws://localhost:{settings.port}" - f"/nostrclient/api/v1/{relay_endpoint}" + f"ws://localhost:{settings.port}" f"/nostrclient/api/v1/{relay_endpoint}" ) logger.info("[EVENTS] Connecting to nostrclient WebSocket...") @@ -58,12 +57,8 @@ class NostrClient: logger.warning(f"[EVENTS] WebSocket error: {error}") def on_close(_, status_code, message): - logger.warning( - f"[EVENTS] WebSocket closed: {status_code} {message}" - ) - self.receive_event_queue.put_nowait( - ValueError("WebSocket closed") - ) + logger.warning(f"[EVENTS] WebSocket closed: {status_code} {message}") + self.receive_event_queue.put_nowait(ValueError("WebSocket closed")) ws = WebSocketApp( ws_url, @@ -118,9 +113,7 @@ class NostrClient: async def subscribe(self, filters: list[dict]): """Subscribe to events matching the given filters.""" self.subscription_id = "events-" + urlsafe_short_hash()[:32] - await self.send_req_queue.put( - ["REQ", self.subscription_id, *filters] - ) + await self.send_req_queue.put(["REQ", self.subscription_id, *filters]) logger.info( f"[EVENTS] Subscribed to NIP-52 events " f"(sub: {self.subscription_id[:20]}...)" diff --git a/nostr_publisher.py b/nostr_publisher.py index bbee871..a6d487b 100644 --- a/nostr_publisher.py +++ b/nostr_publisher.py @@ -78,7 +78,7 @@ def build_nip52_event(event: Event, pubkey: str) -> NostrEvent: tags.append(["image", event.banner]) if event.location: tags.append(["location", event.location]) - for cat in (event.categories or []): + for cat in event.categories or []: tags.append(["t", cat]) nostr_event = NostrEvent( diff --git a/nostr_sync.py b/nostr_sync.py index 380da3c..1dc52bc 100644 --- a/nostr_sync.py +++ b/nostr_sync.py @@ -137,9 +137,11 @@ async def wait_for_nostr_events(nostr_client: NostrClient): while True: try: # Subscribe to NIP-52 calendar events - await nostr_client.subscribe([ - {"kinds": [31922, 31923]}, - ]) + await nostr_client.subscribe( + [ + {"kinds": [31922, 31923]}, + ] + ) # Process incoming events while True: diff --git a/views_api.py b/views_api.py index 36a444b..08e94ab 100644 --- a/views_api.py +++ b/views_api.py @@ -161,9 +161,7 @@ async def api_get_event(event_id: str) -> Event: # closing_date is filled in by create_event (defaults to end_date or # start_date) but the field is typed Optional, so guard for the typechecker. - closing_date = ( - event.closing_date or event.event_end_date or event.event_start_date - ) + closing_date = event.closing_date or event.event_end_date or event.event_start_date # Accept either YYYY-MM-DD or full ISO 8601 datetime (event_end_date # may carry a time component since v1.3.0-aio.3 / our start-end-time # feature). @@ -210,10 +208,7 @@ async def api_event_create( ext_settings = await get_settings() user_id = wallet.wallet.user - is_admin = ( - user_id == settings.super_user - or user_id in settings.lnbits_admin_users - ) + is_admin = user_id == settings.super_user or user_id in settings.lnbits_admin_users if not is_admin and not ext_settings.auto_approve: data.status = "proposed" @@ -249,9 +244,7 @@ async def api_event_update( status_code=HTTPStatus.NOT_FOUND, detail="Event does not exist." ) if event.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not your event." - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your event.") from lnbits.settings import settings @@ -292,7 +285,6 @@ async def api_event_update( event.status = "approved" if (is_admin or ext_settings.auto_approve) else "proposed" - event = await update_event(event) if event.status == "approved":