Commit graph

15 commits

Author SHA1 Message Date
a44de1aa3f feat: "Email sent" column and per-event copy-to-organizer BCC
Organizers had no way to see whether a ticket email went out short of
reading the Postfix journal, and no copy of what the attendee received —
LNbits submits over SMTP, so nothing lands in a Sent folder.

- Admin ticket table gains an "Email sent" column derived from
  `extra.email_notification_sent` ("✓ sent" / "not sent" / "unpaid" /
  "no email").
- `extra.copy_to_organizer`: BCC every ticket email to the event's
  reply-to address (explicit, else the owner's account email) on the SMTP
  envelope only — no Bcc/To header, and skipped when the buyer *is* that
  address. Toggle sits with the other delivery switches in the admin form.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo
2026-09-13 18:19:33 +02:00
72b9c540f7 feat: per-event organizer name + reply-to on ticket emails
Some checks failed
lint.yml / feat: per-event organizer name + reply-to on ticket emails (pull_request) Failing after 0s
Each organizer is different, so the sender identity of ticket emails is
now per event rather than per instance:

- `extra.organizer_name` → From display name "Organizer via <site title>"
  (site title alone when unset). The From address stays the instance
  mailbox — that is what DKIM signs — so this costs nothing in mail auth.
- `extra.reply_to_email` → Reply-To; blank falls back to the email on the
  LNbits account that owns the event wallet; no header when neither
  exists. When a reply-to exists the body says "Questions? Reply to this
  email and it reaches <organizer>", and "Organizer: <name>" is listed
  with the ticket details.

Both fields sit next to the existing per-event subject/body in the admin
dialog. The organizer's own wording (in whatever language) remains
`notification_body`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo
2026-09-13 18:19:33 +02:00
f835766935 feat(admin): event form parity with the webapp (1.6.1-aio.13)
Some checks failed
lint.yml / feat(admin): event form parity with the webapp (1.6.1-aio.13) (pull_request) Failing after 0s
lint.yml / feat(admin): event form parity with the webapp (1.6.1-aio.13) (push) Failing after 0s
The LNbits admin form lagged the webapp's CreateEventDialog:

- Payment methods never rendered. c2d9a96 wired the template to
  `paymentMethodOptions` / `acceptsFiat` but never defined them, so the
  q-option-group got `options=undefined` and the fiat-currency select
  was gated on `undefined`. Rails are now two q-checkboxes; Card is
  disabled with an explanatory tooltip when `g.user.fiat_providers` is
  empty (same rule as the webapp) and names the providers otherwise.
- Location (NIP-52 `location` tag) and Categories (NIP-52 `t` tags,
  same 25-item list as the webapp's category.ts) were missing from the
  form even though the model, CRUD and publisher already carry them.
- Datetimes are stamped with the browser's UTC offset on submit, as the
  webapp does; `_to_unix` treats naive values as UTC, so 18:00 CEST
  entered here went out on Nostr as 18:00 UTC. Table columns render
  "YYYY-MM-DD HH:MM" instead of the raw ISO string.
- Validation: title + start date required, end >= start on the folded
  date+time, fiat currency required when a sat-priced event accepts
  card. Create is enabled once wallet + title + start are set; info,
  closing date, tickets and price were all effectively required before
  because the disable check compared undefined fields to null.
- Labels follow the payment-rails vocabulary: "Unit" -> "Price
  currency", "Fiat checkout currency" -> "Fiat currency"; ticket
  closing date and end date explain their defaults.
- A fiat-priced event mirrors `fiat_currency = currency` on save so the
  payload and the `tickets_fiat_currency` tag stay coherent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018b1bDExMX7W3a47wcgFUjb
2026-09-10 13:43:53 +02:00
c2d9a96239 feat: per-event payment methods (extra.payment_methods)
Organizers pick which rails an event accepts — Lightning, card (fiat) or
both — instead of a bare "allow fiat" toggle. `extra.payment_methods`
uses the field name upstream v2 (lnbits/events#64) introduces so the
eventual rebase merges cleanly; an empty list keeps the legacy rule
(Lightning always, fiat when allow_fiat), and allow_fiat stays the
fiat-currency carrier, kept in lockstep on save. The effective list is
published as the NIP-52 tag `tickets_payment_methods` so clients render
exactly the buttons the purchase endpoint will accept, and the buyer page
defaults to the first accepted rail (a card-only event never submits
"lightning").

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo
2026-09-06 19:53:05 +02:00
3606fd9a0a feat(admin): Owner column on All Users' Events card
Some checks failed
lint.yml / feat(admin): Owner column on All Users' Events card (pull_request) Failing after 0s
Adds the event's wallet owner (user_id) as the first column of the
admin-only All Users' Events table so cross-tenant rows are
attributable at a glance. Server-side join: GET /events/all now
resolves each event.wallet -> wallet.user and stamps the result on
the response as wallet_user_id. Frontend gets a dedicated
allUsersEventsTable.columns definition so the user's own-events
table stays unchanged.

Follow-up #22 covers letting the admin actually edit those events
once attributed.
2026-05-24 18:51:51 +02:00
66d263ef14 ui(admin): Tickets card above All Users' Events on the admin index
Some checks failed
lint.yml / ui(admin): Tickets card above All Users' Events on the admin index (pull_request) Failing after 0s
The Tickets table is what an organiser actually scans during day-of
operations — it deserves the top slot. All Users' Events stays one
section down for the cross-tenant audit view (admin-only anyway).
2026-05-24 18:46:18 +02:00
ced6ca2b2b feat: organizer-side "Republish mine" button + scoped endpoint
The admin /republish-all hits every approved event regardless of
owner — useful for the catalog migration, but heavy. Organizers
who want to re-emit just THEIR own events (e.g. after the AIO
publisher gained the tickets_* tags and an organizer's events
should pick them up) need a lighter knob.

Backend: new POST /republish-mine wallet-scoped via require_admin_key,
mirrors api_tickets's `all_wallets=true` shape so the page can
re-emit across every wallet the user owns. Filters to approved +
non-canceled rows.

UI: "Republish mine" button alongside "New Event" so every
logged-in user sees it (no isAdmin gate). Loading state +
confirm dialog + success count notification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 21:02:36 +02:00
fa2a6e40f0 feat(ui): "Republish all" button on the admin Settings card
Surfaces the POST /republish-all endpoint added in the previous
commit. Lives in the existing admin-gated Settings card on the
events extension landing page, so the LNbits operator can trigger
the migration without curl + access tokens.

Confirm dialog before firing (the endpoint emits one Nostr event
per approved row, fine to retry but worth a click of friction).
Notification shows the republished/total count on success.

Self-closing tags expanded per the LNbits UMD rule
(webapp CLAUDE.md > LNbits + Quasar UMD gotchas) — q-separator
and q-btn would silently nest wrong otherwise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 21:00:30 +02:00
df4775126f feat: support optional start/end time on events
event_start_date / event_end_date now accept either YYYY-MM-DD (date-only)
or YYYY-MM-DDTHH:MM (ISO datetime). The NIP-52 publisher switches kind
on the "T" delimiter: kind 31922 (date-based, YYYY-MM-DD start/end) when
absent, kind 31923 (time-based, unix-timestamp start/end + day-granularity
D tags) when present. Delete events match the original publish kind.

Closing-date parsing accepts both formats. The LNbits admin form gains
optional HH:MM inputs alongside each date picker; they fold into the
wire-format string on submit and split back on edit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 09:21:30 +02:00
c7e95c5452 feat: add event approval workflow with admin UI
Non-admin event submissions now land in a "proposed" queue that LNbits
admins review before the event becomes ticketable and publicly listed.

- m008 adds events.events.status (proposed/approved/rejected); m010 seeds
  an events.settings singleton row with the auto_approve toggle.
- Models: Event/CreateEvent.status, EventsSettings, optional date fields
  with sensible defaults (closing_date defaults to event_end_date which
  defaults to event_start_date), PublicEvent.status surfaces the workflow
  state on the public endpoint.
- crud: get_all/public/pending_events for the admin views; get/update_settings
  for the auto_approve toggle; create_event auto-fills missing date defaults.
- views_api:
  * POST /api/v1/events accepts wallet invoice keys so anyone can submit;
    handler stamps status="proposed" for non-admins when auto_approve is off
  * /public, /all, /pending, /settings (GET+PUT), /{id}/{approve,reject},
    /{id}/tickets endpoints; literal-prefix routes declared before /{event_id}
    so FastAPI matches them correctly
  * Public GET /{event_id} bypasses sold-out / closing-window gates for
    proposed/rejected events and returns the trimmed PublicEvent so the SFC
    can render a "pending approval" banner
  * POST /tickets/{event_id} rejects when event.status != "approved"
- Frontend: index.vue gains an admin Settings card, Pending Approvals list,
  status badge column and approve/reject row actions, plus an All Users'
  Events admin table; index.js gains the data + methods + an isAdmin probe
  via GET /events/all; display.vue shows pending/rejected banners and
  hides the Buy Ticket form unless status === "approved".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 09:19:21 +02:00
dni ⚡
4bf867eef0
feat: add resend email button to ticket list (#51)
- resending only possible when ticket is paid.
2026-05-13 11:30:14 +02:00
Arc
6768b78c6f Custom subject and body 2026-05-08 19:14:07 +01:00
Arc
32c230957e fix: if sats and fiat checkout conversion currency 2026-05-07 14:34:22 +01:00
Arc
680b035ec9
feat: add fiat checkout and nostr + email notification (#50)
* feat: fiat and email/nostr notifications

* make n bake
2026-05-07 12:31:32 +01:00
Tiago Vasconcelos
9e477ac959
feat: make events dynamic (#43)
---------

Co-authored-by: dni <office@dnilabs.com>
2026-05-04 17:01:53 +02:00