2026-03-03 12:50:24 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
func TestParticipantsListCreateDelete(t *testing.T) {
|
2026-03-03 12:50:24 -06:00
|
|
|
app := testApp(t)
|
|
|
|
|
admin := testAdminUser(t, app)
|
|
|
|
|
token := testToken(t, app, admin)
|
|
|
|
|
mux := testMux(app)
|
|
|
|
|
|
|
|
|
|
// Create
|
2026-03-04 15:27:03 -06:00
|
|
|
req := testAuthRequest("POST", "/api/participants", map[string]string{"preferred_name": "Titania", "email": "titania@example.com"}, token)
|
2026-03-03 12:50:24 -06:00
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
mux.ServeHTTP(w, req)
|
|
|
|
|
if w.Code != http.StatusCreated {
|
|
|
|
|
t.Fatalf("create: status = %d\nbody: %s", w.Code, w.Body.String())
|
|
|
|
|
}
|
|
|
|
|
created := parseJSON(t, w)
|
|
|
|
|
id := created["id"].(float64)
|
|
|
|
|
|
|
|
|
|
// List
|
2026-03-04 15:27:03 -06:00
|
|
|
req = testAuthRequest("GET", "/api/participants", nil, token)
|
2026-03-03 12:50:24 -06:00
|
|
|
w = httptest.NewRecorder()
|
|
|
|
|
mux.ServeHTTP(w, req)
|
|
|
|
|
if w.Code != http.StatusOK {
|
|
|
|
|
t.Fatalf("list: status = %d", w.Code)
|
|
|
|
|
}
|
|
|
|
|
list := parseJSON(t, w)
|
2026-03-04 15:27:03 -06:00
|
|
|
participants := list["participants"].([]any)
|
|
|
|
|
if len(participants) != 1 {
|
|
|
|
|
t.Errorf("list: got %d, want 1", len(participants))
|
2026-03-03 12:50:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Delete
|
2026-03-04 15:27:03 -06:00
|
|
|
req = testAuthRequest("DELETE", "/api/participants/"+itoa(int(id)), nil, token)
|
2026-03-03 12:50:24 -06:00
|
|
|
w = httptest.NewRecorder()
|
|
|
|
|
mux.ServeHTTP(w, req)
|
|
|
|
|
if w.Code != http.StatusNoContent {
|
|
|
|
|
t.Errorf("delete: status = %d", w.Code)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// List again — should be empty
|
2026-03-04 15:27:03 -06:00
|
|
|
req = testAuthRequest("GET", "/api/participants", nil, token)
|
2026-03-03 12:50:24 -06:00
|
|
|
w = httptest.NewRecorder()
|
|
|
|
|
mux.ServeHTTP(w, req)
|
|
|
|
|
list = parseJSON(t, w)
|
2026-03-04 15:27:03 -06:00
|
|
|
if ps, ok := list["participants"].([]any); ok && len(ps) != 0 {
|
|
|
|
|
t.Errorf("after delete: got %d, want 0", len(ps))
|
2026-03-03 12:50:24 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
func TestCheckInTicketHandler(t *testing.T) {
|
2026-03-03 12:50:24 -06:00
|
|
|
app := testApp(t)
|
|
|
|
|
admin := testAdminUser(t, app)
|
|
|
|
|
token := testToken(t, app, admin)
|
|
|
|
|
mux := testMux(app)
|
|
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
p, _ := app.createParticipant(Participant{PreferredName: "Oberon", Email: "oberon@example.com"})
|
|
|
|
|
tk, _ := app.createTicket(Ticket{ParticipantID: &p.ID, Name: "Oberon", Source: "manual"})
|
2026-03-03 12:50:24 -06:00
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
req := testAuthRequest("POST", "/api/tickets/"+itoa(tk.ID)+"/checkin", nil, token)
|
2026-03-03 12:50:24 -06:00
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
mux.ServeHTTP(w, req)
|
|
|
|
|
if w.Code != http.StatusOK {
|
|
|
|
|
t.Fatalf("checkin: status = %d\nbody: %s", w.Code, w.Body.String())
|
|
|
|
|
}
|
|
|
|
|
result := parseJSON(t, w)
|
2026-03-04 15:27:03 -06:00
|
|
|
ticket := result["ticket"].(map[string]any)
|
|
|
|
|
if ticket["checked_in_at"] == nil {
|
|
|
|
|
t.Error("checked_in_at should be set after check-in")
|
2026-03-03 12:50:24 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
func TestGatekeeperRoleCanCheckIn(t *testing.T) {
|
2026-03-03 12:50:24 -06:00
|
|
|
app := testApp(t)
|
2026-03-04 12:00:36 -06:00
|
|
|
gate := testUserWithRole(t, app, "gateuser", "gatekeeper", []int{})
|
2026-03-03 12:50:24 -06:00
|
|
|
token := testToken(t, app, gate)
|
|
|
|
|
mux := testMux(app)
|
|
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
p, _ := app.createParticipant(Participant{PreferredName: "Puck", Email: "puck@example.com"})
|
|
|
|
|
tk, _ := app.createTicket(Ticket{ParticipantID: &p.ID, Name: "Puck", Source: "manual"})
|
2026-03-03 12:50:24 -06:00
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
req := testAuthRequest("POST", "/api/tickets/"+itoa(tk.ID)+"/checkin", nil, token)
|
2026-03-03 12:50:24 -06:00
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
mux.ServeHTTP(w, req)
|
|
|
|
|
if w.Code != http.StatusOK {
|
2026-03-04 15:27:03 -06:00
|
|
|
t.Errorf("gatekeeper checkin: status = %d", w.Code)
|
2026-03-03 12:50:24 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
func TestGatekeeperRoleCannotDelete(t *testing.T) {
|
2026-03-03 12:50:24 -06:00
|
|
|
app := testApp(t)
|
2026-03-04 12:00:36 -06:00
|
|
|
gate := testUserWithRole(t, app, "gateuser", "gatekeeper", []int{})
|
2026-03-03 12:50:24 -06:00
|
|
|
token := testToken(t, app, gate)
|
|
|
|
|
mux := testMux(app)
|
|
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
p, _ := app.createParticipant(Participant{PreferredName: "Puck", Email: "puck@example.com"})
|
2026-03-03 12:50:24 -06:00
|
|
|
|
2026-03-04 15:27:03 -06:00
|
|
|
req := testAuthRequest("DELETE", "/api/participants/"+itoa(p.ID), nil, token)
|
2026-03-03 12:50:24 -06:00
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
mux.ServeHTTP(w, req)
|
|
|
|
|
if w.Code != http.StatusForbidden {
|
2026-03-04 15:27:03 -06:00
|
|
|
t.Errorf("gatekeeper delete: status = %d, want 403", w.Code)
|
2026-03-03 12:50:24 -06:00
|
|
|
}
|
|
|
|
|
}
|