Turnpike/handle_tokens.go

99 lines
2.8 KiB
Go
Raw Normal View History

package main
import (
"encoding/csv"
"fmt"
"net/http"
"strconv"
"strings"
)
// handleGenerateTokens creates volunteer_token values for all attendees that don't have one.
func (app *App) handleGenerateTokens(w http.ResponseWriter, r *http.Request) {
count, err := app.generateTokensForAll()
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) {
attendees, err := app.listAttendees("", "", "")
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 _, a := range attendees {
if a.VolunteerToken == nil {
continue
}
firstName := a.Name
if parts := strings.Fields(a.Name); len(parts) > 0 {
firstName = parts[0]
}
link := fmt.Sprintf("%s/v/%s", baseURL, *a.VolunteerToken)
wr.Write([]string{a.Email, firstName, *a.VolunteerToken, link})
}
wr.Flush()
}
// handleEmailToken sends a token email to a single attendee.
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
}
a, err := app.getAttendee(id)
if err != nil || a == nil {
writeError(w, "not found", http.StatusNotFound)
return
}
if err := app.sendTokenEmail(*a); err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
writeJSON(w, map[string]any{"ok": true})
}
// handleEmailAllTokens bulk-sends token emails to all attendees that have both a token and email.
func (app *App) handleEmailAllTokens(w http.ResponseWriter, r *http.Request) {
attendees, err := app.listAttendees("", "", "")
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
var sent, skipped int
var errors []string
for _, a := range attendees {
if a.Email == "" || a.VolunteerToken == nil {
skipped++
continue
}
if err := app.sendTokenEmail(a); err != nil {
errors = append(errors, fmt.Sprintf("%s: %v", a.Name, err))
skipped++
} else {
sent++
}
}
if errors == nil {
errors = []string{}
}
writeJSON(w, map[string]any{"sent": sent, "skipped": skipped, "errors": errors})
}