chore: rebase onto upstream v1.6.1 + bump to v1.6.1-aio.1
Some checks failed
lint.yml / chore: rebase onto upstream v1.6.1 + bump to v1.6.1-aio.1 (push) Failing after 0s

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) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-22 09:24:35 +02:00
commit 27cc8d2f1c
7 changed files with 22 additions and 34 deletions

View file

@ -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)

View file

@ -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": [

View file

@ -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

View file

@ -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]}...)"

View file

@ -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(

View file

@ -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:

View file

@ -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":