Turnpike/handle_tokens.go

106 lines
2.9 KiB
Go
Raw Normal View History

package main
import (
"encoding/csv"
"fmt"
"net/http"
"strconv"
"strings"
)
// handleGenerateTokens creates codes for all tickets that don't have one.
func (app *App) handleGenerateTokens(w http.ResponseWriter, r *http.Request) {
count, err := app.generateCodesForAll()
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
writeJSON(w, map[string]any{"generated": count})
}
// handleExportTokenLinks streams a CSV download with token signup links,
// compatible with MailChimp / Zeffy bulk-send workflows.
func (app *App) handleExportTokenLinks(w http.ResponseWriter, r *http.Request) {
tickets, err := app.listTickets(nil, "")
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
baseURL := app.baseURL
if baseURL == "" {
app.db.QueryRow(`SELECT value FROM config WHERE key = 'base_url'`).Scan(&baseURL)
}
baseURL = strings.TrimRight(baseURL, "/")
w.Header().Set("Content-Type", "text/csv")
w.Header().Set("Content-Disposition", `attachment; filename="volunteer-tokens.csv"`)
wr := csv.NewWriter(w)
wr.Write([]string{"Email Address", "First Name", "Token", "Signup Link"})
for _, tk := range tickets {
if tk.Code == nil || tk.ParticipantID == nil {
continue
}
p, _ := app.getParticipant(*tk.ParticipantID)
if p == nil || p.Email == "" {
continue
}
firstName := p.PreferredName
if firstName == "" {
firstName = tk.Name
}
if parts := strings.Fields(firstName); len(parts) > 0 {
firstName = parts[0]
}
link := fmt.Sprintf("%s/v/%s", baseURL, *tk.Code)
wr.Write([]string{p.Email, firstName, *tk.Code, link})
}
wr.Flush()
}
// handleEmailToken sends a token email to a single ticket's participant.
func (app *App) handleEmailToken(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, "invalid id", http.StatusBadRequest)
return
}
tk, err := app.getTicket(id)
if err != nil || tk == nil {
writeError(w, "not found", http.StatusNotFound)
return
}
if err := app.sendTicketTokenEmail(*tk); err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
writeJSON(w, map[string]any{"ok": true})
}
// handleEmailAllTokens bulk-sends token emails to all tickets that have a code and participant email.
func (app *App) handleEmailAllTokens(w http.ResponseWriter, r *http.Request) {
tickets, err := app.listTickets(nil, "")
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
var sent, skipped int
var errors []string
for _, tk := range tickets {
if tk.Code == nil || tk.ParticipantID == nil {
skipped++
continue
}
if err := app.sendTicketTokenEmail(tk); err != nil {
errors = append(errors, fmt.Sprintf("ticket %d: %v", tk.ID, err))
skipped++
} else {
sent++
}
}
if errors == nil {
errors = []string{}
}
writeJSON(w, map[string]any{"sent": sent, "skipped": skipped, "errors": errors})
}