Created Turnpike, event attendee and volunteer management
Built after prototype, Traverse, an attendee and volunteer list maintainer.
This commit is contained in:
commit
5d56ba8112
59 changed files with 8663 additions and 0 deletions
132
handle_kiosk.go
Normal file
132
handle_kiosk.go
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// handleKioskGet returns the volunteer's profile, current shift assignments, and
|
||||
// available open shifts in their department. Authenticated by volunteer token only —
|
||||
// no JWT required.
|
||||
func (app *App) handleKioskGet(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.PathValue("token")
|
||||
a, err := app.getAttendeeByToken(token)
|
||||
if err != nil || a == nil {
|
||||
writeError(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
v, _ := app.getVolunteerByAttendeeID(a.ID)
|
||||
if v == nil {
|
||||
writeError(w, "no volunteer record linked to this token", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
assigned, _ := app.listShiftsForVolunteer(v.ID)
|
||||
if assigned == nil {
|
||||
assigned = []Shift{}
|
||||
}
|
||||
|
||||
var available []Shift
|
||||
if v.DepartmentID != nil {
|
||||
available, _ = app.listOpenShiftsForDept(*v.DepartmentID)
|
||||
}
|
||||
if available == nil {
|
||||
available = []Shift{}
|
||||
}
|
||||
|
||||
writeJSON(w, map[string]any{
|
||||
"volunteer": v,
|
||||
"shifts": assigned,
|
||||
"available": available,
|
||||
})
|
||||
}
|
||||
|
||||
// handleKioskClaim assigns the volunteer to a shift.
|
||||
// Without ?force=true it returns 409 with conflicting shifts on overlap.
|
||||
func (app *App) handleKioskClaim(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.PathValue("token")
|
||||
shiftID, err := strconv.Atoi(r.PathValue("id"))
|
||||
if err != nil {
|
||||
writeError(w, "invalid shift id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
a, err := app.getAttendeeByToken(token)
|
||||
if err != nil || a == nil {
|
||||
writeError(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
v, _ := app.getVolunteerByAttendeeID(a.ID)
|
||||
if v == nil {
|
||||
writeError(w, "no volunteer linked to this token", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
force := r.URL.Query().Get("force") == "true"
|
||||
|
||||
if !force {
|
||||
conflicts, err := app.checkShiftConflict(v.ID, shiftID)
|
||||
if err != nil {
|
||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if len(conflicts) > 0 {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
writeJSON(w, map[string]any{
|
||||
"conflict": true,
|
||||
"conflicting_shifts": conflicts,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
shift, err := app.getShift(shiftID)
|
||||
if err != nil || shift == nil {
|
||||
writeError(w, "shift not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if shift.Capacity > 0 {
|
||||
count, _ := app.shiftAssignedCount(shiftID)
|
||||
if count >= shift.Capacity {
|
||||
writeError(w, "shift is full", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := app.assignShift(v.ID, shiftID); err != nil {
|
||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
app.handleKioskGet(w, r)
|
||||
}
|
||||
|
||||
// handleKioskUnclaim removes the volunteer from a shift.
|
||||
func (app *App) handleKioskUnclaim(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.PathValue("token")
|
||||
shiftID, err := strconv.Atoi(r.PathValue("id"))
|
||||
if err != nil {
|
||||
writeError(w, "invalid shift id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
a, err := app.getAttendeeByToken(token)
|
||||
if err != nil || a == nil {
|
||||
writeError(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
v, _ := app.getVolunteerByAttendeeID(a.ID)
|
||||
if v == nil {
|
||||
writeError(w, "no volunteer linked to this token", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if err := app.unassignShift(v.ID, shiftID); err != nil {
|
||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
app.handleKioskGet(w, r)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue