Turnpike/handle_participants.go

157 lines
4.5 KiB
Go

package main
import (
"encoding/csv"
"encoding/json"
"net/http"
"strconv"
)
func (app *App) handleListParticipants(w http.ResponseWriter, r *http.Request) {
search := r.URL.Query().Get("search")
participants, err := app.listParticipants(search, "")
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
total, checkedIn, _ := app.ticketCounts()
types, _ := app.ticketTypes()
writeJSON(w, map[string]any{
"participants": participants,
"total": total,
"checked_in": checkedIn,
"ticket_types": types,
})
}
func (app *App) handleGetParticipant(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, "invalid id", http.StatusBadRequest)
return
}
p, err := app.getParticipant(id)
if err != nil || p == nil {
writeError(w, "not found", http.StatusNotFound)
return
}
tickets, _ := app.listTickets(&id, "")
writeJSON(w, map[string]any{"participant": p, "tickets": tickets})
}
func (app *App) handleCreateParticipant(w http.ResponseWriter, r *http.Request) {
var p Participant
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
writeError(w, "invalid request", http.StatusBadRequest)
return
}
if p.PreferredName == "" && p.Email == "" {
writeError(w, "name or email is required", http.StatusBadRequest)
return
}
created, err := app.createParticipant(p)
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
writeJSON(w, created)
}
func (app *App) handleUpdateParticipant(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, "invalid id", http.StatusBadRequest)
return
}
var p Participant
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
writeError(w, "invalid request", http.StatusBadRequest)
return
}
p.ID = id
if err := app.updateParticipant(p); err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
updated, _ := app.getParticipant(id)
writeJSON(w, updated)
}
func (app *App) handleDeleteParticipant(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, "invalid id", http.StatusBadRequest)
return
}
if err := app.deleteParticipant(id); err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
// handleMergeParticipants reassigns all tickets and volunteers from otherID to
// canonicalID, then soft-deletes the other participant.
func (app *App) handleMergeParticipants(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, "invalid id", http.StatusBadRequest)
return
}
otherID, err := strconv.Atoi(r.PathValue("other_id"))
if err != nil {
writeError(w, "invalid other_id", http.StatusBadRequest)
return
}
if err := app.mergeParticipants(id, otherID); err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
p, _ := app.getParticipant(id)
tickets, _ := app.listTickets(&id, "")
writeJSON(w, map[string]any{"participant": p, "tickets": tickets})
}
func (app *App) handleExportParticipants(w http.ResponseWriter, r *http.Request) {
participants, err := app.listParticipants("", "")
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/csv")
w.Header().Set("Content-Disposition", `attachment; filename="participants.csv"`)
wr := csv.NewWriter(w)
wr.Write([]string{"id", "email", "preferred_name", "phone", "pronouns", "note"})
for _, p := range participants {
wr.Write([]string{
strconv.Itoa(p.ID), p.Email, p.PreferredName, p.Phone, p.Pronouns, p.Note,
})
}
wr.Flush()
}
func (app *App) handleListTickets(w http.ResponseWriter, r *http.Request) {
tickets, err := app.listTickets(nil, "")
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
writeJSON(w, map[string]any{"tickets": tickets})
}
func (app *App) handleCheckInTicket(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, "invalid id", http.StatusBadRequest)
return
}
claims := claimsFromContext(r)
tk, err := app.checkInTicket(id, claims.UserID)
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
app.broker.publish("checkin", map[string]any{"type": "ticket", "ticket": tk})
writeJSON(w, map[string]any{"ticket": tk})
}