Established Participants and Tickets model. Migrated concepts.
This commit is contained in:
parent
0df93e1886
commit
cd8e1e3b3b
22 changed files with 1345 additions and 191 deletions
157
handle_participants.go
Normal file
157
handle_participants.go
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
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})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue