From ea461a52ac62c7d3bd3fdd35a706f299b695a102 Mon Sep 17 00:00:00 2001 From: dni Date: Wed, 13 May 2026 10:22:26 +0200 Subject: [PATCH] feat: add resend email button to ticket list - resending only possible when ticket is paid. --- config.json | 2 +- services.py | 42 +++++++++++++++++++++++++++++++----------- static/js/index.js | 30 ++++++++++++++++++++++++++++++ static/js/index.vue | 16 ++++++++++++++++ views_api.py | 34 +++++++++++++++++++++++++++++++++- 5 files changed, 111 insertions(+), 13 deletions(-) diff --git a/config.json b/config.json index 11bd0b1..a945b43 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "id": "events", - "version": "1.3.0", + "version": "1.6.1", "name": "Events", "repo": "https://github.com/lnbits/events", "short_description": "Sell and register event tickets", diff --git a/services.py b/services.py index 479aaa1..159bbdc 100644 --- a/services.py +++ b/services.py @@ -20,7 +20,7 @@ update_event, update_ticket, ) -from .models import Ticket +from .models import Event, Ticket DEFAULT_NOSTR_RELAYS = [ "wss://relay.damus.io", @@ -55,16 +55,7 @@ async def _send_ticket_notification(ticket: Ticket) -> None: logger.warning(f"Event {ticket.event} not found for ticket notification.") return - ticket_url = _ticket_url(ticket) - subject = ( - event.extra.notification_subject.strip() - or f"Your ticket for '{event.name}' is ready" - ) - body = ( - event.extra.notification_body.strip() - or f"Your ticket for '{event.name}' is ready." - ) - message = f"{body}\n\nOpen it here: {ticket_url}" + subject, message = _ticket_notification_message(ticket, event) updated = False if ( @@ -97,6 +88,35 @@ async def _send_ticket_notification(ticket: Ticket) -> None: await update_ticket(ticket) +async def resend_ticket_email_notification(ticket: Ticket) -> Ticket: + event = await get_event(ticket.event) + if not event: + raise ValueError("Event does not exist.") + if not settings.lnbits_email_notifications_enabled: + raise ValueError("Email notifications are not enabled.") + if not ticket.email: + raise ValueError("Ticket does not have an email address.") + + subject, message = _ticket_notification_message(ticket, event) + await send_email_notification([ticket.email], message, subject) + ticket.extra.email_notification_sent = True + return await update_ticket(ticket) + + +def _ticket_notification_message(ticket: Ticket, event: Event) -> tuple[str, str]: + ticket_url = _ticket_url(ticket) + subject = ( + event.extra.notification_subject.strip() + or f"Your ticket for '{event.name}' is ready" + ) + body = ( + event.extra.notification_body.strip() + or f"Your ticket for '{event.name}' is ready." + ) + + return subject, f"{body}\n\nOpen it here: {ticket_url}" + + async def _send_nostr_ticket_notification(identifier: str, message: str) -> None: if "@" in identifier: await send_user_notification( diff --git a/static/js/index.js b/static/js/index.js index d53ed90..5424a32 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -4,6 +4,7 @@ window.PageEvents = { return { events: [], tickets: [], + resendingTicketEmails: [], currencies: [], eventsTable: { columns: [ @@ -145,6 +146,35 @@ window.PageEvents = { .catch(LNbits.utils.notifyApiError) }) }, + resendTicketEmail(ticket) { + if (!ticket.paid || !ticket.email) return + const wallet = _.findWhere(this.g.user.wallets, {id: ticket.wallet}) + if (!wallet) return + + this.resendingTicketEmails.push(ticket.id) + LNbits.api + .request( + 'POST', + '/events/api/v1/tickets/' + ticket.id + '/resend-email', + wallet.adminkey + ) + .then(response => { + this.tickets = this.tickets.map(obj => + obj.id === ticket.id ? response.data : obj + ) + Quasar.Notify.create({ + type: 'positive', + message: 'Ticket email resent.', + icon: null + }) + }) + .catch(LNbits.utils.notifyApiError) + .finally(() => { + this.resendingTicketEmails = this.resendingTicketEmails.filter( + ticketId => ticketId !== ticket.id + ) + }) + }, exportticketsCSV() { LNbits.utils.exportCSV(this.ticketsTable.columns, this.tickets) }, diff --git a/static/js/index.vue b/static/js/index.vue index 0c21058..fa39a4e 100644 --- a/static/js/index.vue +++ b/static/js/index.vue @@ -171,10 +171,12 @@ >