feat: event proposal and approval workflow #9
1 changed files with 47 additions and 0 deletions
feat: publish NIP-52 events on approve/create/update/cancel/delete
Some checks failed
lint.yml / feat: publish NIP-52 events on approve/create/update/cancel/delete (pull_request) Failing after 0s
Some checks failed
lint.yml / feat: publish NIP-52 events on approve/create/update/cancel/delete (pull_request) Failing after 0s
- On approve: publish kind 31922 calendar event to Nostr - On admin create (auto-approved): publish immediately - On update (approved event): republish (kind 31922 is replaceable) - On cancel/delete: publish kind 5 delete event - All Nostr calls are wrapped in try/except for graceful degradation - Event creator's Account keypair used for signing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
commit
2db0102857
47
views_api.py
47
views_api.py
|
|
@ -35,11 +35,38 @@ from .crud import (
|
||||||
update_ticket,
|
update_ticket,
|
||||||
)
|
)
|
||||||
from .models import CreateEvent, CreateTicket, Ticket
|
from .models import CreateEvent, CreateTicket, Ticket
|
||||||
|
from .nostr_publisher import publish_event_to_nostr
|
||||||
from .services import refund_tickets, set_ticket_paid
|
from .services import refund_tickets, set_ticket_paid
|
||||||
|
|
||||||
events_api_router = APIRouter()
|
events_api_router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
async def _publish_or_delete_nostr_event(event, delete=False):
|
||||||
|
"""Publish (or delete) a NIP-52 calendar event using the creator's keypair."""
|
||||||
|
try:
|
||||||
|
from lnbits.core.crud.wallets import get_wallet
|
||||||
|
from lnbits.core.crud.users import get_account
|
||||||
|
|
||||||
|
from . import nostr_client
|
||||||
|
|
||||||
|
wallet_obj = await get_wallet(event.wallet)
|
||||||
|
if not wallet_obj:
|
||||||
|
return
|
||||||
|
account = await get_account(wallet_obj.user)
|
||||||
|
if not account or not account.pubkey or not account.prvkey:
|
||||||
|
return
|
||||||
|
|
||||||
|
nostr_event = await publish_event_to_nostr(
|
||||||
|
nostr_client, event, account.pubkey, account.prvkey, delete=delete
|
||||||
|
)
|
||||||
|
if nostr_event and not delete:
|
||||||
|
event.nostr_event_id = nostr_event.id
|
||||||
|
event.nostr_event_created_at = nostr_event.created_at
|
||||||
|
await update_event(event)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"[EVENTS] Nostr publish failed: {e}")
|
||||||
|
|
||||||
|
|
||||||
@events_api_router.get("/api/v1/events")
|
@events_api_router.get("/api/v1/events")
|
||||||
async def api_events(
|
async def api_events(
|
||||||
all_wallets: bool = Query(False),
|
all_wallets: bool = Query(False),
|
||||||
|
|
@ -96,6 +123,10 @@ async def api_event_create(
|
||||||
for k, v in data.dict().items():
|
for k, v in data.dict().items():
|
||||||
setattr(event, k, v)
|
setattr(event, k, v)
|
||||||
event = await update_event(event)
|
event = await update_event(event)
|
||||||
|
|
||||||
|
# Republish to Nostr if event is approved (kind 31922 is replaceable)
|
||||||
|
if event.status == "approved" and event.nostr_event_id:
|
||||||
|
await _publish_or_delete_nostr_event(event)
|
||||||
else:
|
else:
|
||||||
if not data.wallet:
|
if not data.wallet:
|
||||||
data.wallet = wallet.wallet.id
|
data.wallet = wallet.wallet.id
|
||||||
|
|
@ -111,6 +142,10 @@ async def api_event_create(
|
||||||
data.status = "proposed"
|
data.status = "proposed"
|
||||||
event = await create_event(data)
|
event = await create_event(data)
|
||||||
|
|
||||||
|
# Publish to Nostr if auto-approved (admin-created)
|
||||||
|
if event.status == "approved":
|
||||||
|
await _publish_or_delete_nostr_event(event)
|
||||||
|
|
||||||
return event.dict()
|
return event.dict()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -131,6 +166,10 @@ async def api_event_cancel(
|
||||||
event = await update_event(event)
|
event = await update_event(event)
|
||||||
await refund_tickets(event.id)
|
await refund_tickets(event.id)
|
||||||
|
|
||||||
|
# Delete NIP-52 event from Nostr if it was published
|
||||||
|
if event.nostr_event_id:
|
||||||
|
await _publish_or_delete_nostr_event(event, delete=True)
|
||||||
|
|
||||||
return event.dict()
|
return event.dict()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -147,6 +186,10 @@ async def api_form_delete(
|
||||||
if event.wallet != wallet.wallet.id:
|
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.")
|
||||||
|
|
||||||
|
# Delete NIP-52 event from Nostr if it was published
|
||||||
|
if event.nostr_event_id:
|
||||||
|
await _publish_or_delete_nostr_event(event, delete=True)
|
||||||
|
|
||||||
await delete_event(event_id)
|
await delete_event(event_id)
|
||||||
await delete_event_tickets(event_id)
|
await delete_event_tickets(event_id)
|
||||||
return "", HTTPStatus.NO_CONTENT
|
return "", HTTPStatus.NO_CONTENT
|
||||||
|
|
@ -197,6 +240,10 @@ async def api_event_approve(
|
||||||
)
|
)
|
||||||
event.status = "approved"
|
event.status = "approved"
|
||||||
event = await update_event(event)
|
event = await update_event(event)
|
||||||
|
|
||||||
|
# Publish NIP-52 calendar event to Nostr
|
||||||
|
await _publish_or_delete_nostr_event(event)
|
||||||
|
|
||||||
return event.dict()
|
return event.dict()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue