2026-03-03 11:27:07 -06:00
package main
import (
"encoding/json"
"net/http"
"strconv"
)
func ( app * App ) handleGetSettings ( w http . ResponseWriter , r * http . Request ) {
cfg := app . loadSMTPConfig ( )
baseURL := app . baseURL
if baseURL == "" {
app . db . QueryRow ( ` SELECT value FROM config WHERE key = 'base_url' ` ) . Scan ( & baseURL )
}
pass := ""
if cfg . Password != "" {
pass = "***"
}
2026-03-03 17:59:35 -06:00
var noteLabel , noteRequired , signupsOpen string
app . db . QueryRow ( ` SELECT value FROM config WHERE key = 'volunteer_note_label' ` ) . Scan ( & noteLabel )
app . db . QueryRow ( ` SELECT value FROM config WHERE key = 'volunteer_note_required' ` ) . Scan ( & noteRequired )
app . db . QueryRow ( ` SELECT value FROM config WHERE key = 'shift_signups_open' ` ) . Scan ( & signupsOpen )
if noteLabel == "" {
noteLabel = "Additional note"
}
2026-03-03 11:27:07 -06:00
writeJSON ( w , map [ string ] any {
2026-03-03 17:59:35 -06:00
"smtp_host" : cfg . Host ,
"smtp_port" : cfg . Port ,
"smtp_user" : cfg . User ,
"smtp_password" : pass ,
"smtp_from" : cfg . From ,
"smtp_from_name" : cfg . FromName ,
"base_url" : baseURL ,
"volunteer_note_label" : noteLabel ,
"volunteer_note_required" : noteRequired == "true" ,
"shift_signups_open" : signupsOpen == "true" ,
2026-03-03 11:27:07 -06:00
} )
}
func ( app * App ) handleUpdateSettings ( w http . ResponseWriter , r * http . Request ) {
var body map [ string ] any
if err := json . NewDecoder ( r . Body ) . Decode ( & body ) ; err != nil {
writeError ( w , "invalid request" , http . StatusBadRequest )
return
}
2026-03-03 17:59:35 -06:00
keys := [ ] string { "smtp_host" , "smtp_port" , "smtp_user" , "smtp_password" , "smtp_from" , "smtp_from_name" , "base_url" ,
"volunteer_note_label" , "volunteer_note_required" }
2026-03-03 11:27:07 -06:00
for _ , k := range keys {
v , ok := body [ k ]
if ! ok {
continue
}
var val string
switch vv := v . ( type ) {
case string :
if k == "smtp_password" && vv == "" {
2026-03-03 17:59:35 -06:00
continue
2026-03-03 11:27:07 -06:00
}
val = vv
case float64 :
val = strconv . Itoa ( int ( vv ) )
2026-03-03 17:59:35 -06:00
case bool :
if vv {
val = "true"
} else {
val = "false"
}
2026-03-03 11:27:07 -06:00
default :
continue
}
app . db . Exec ( ` INSERT OR REPLACE INTO config (key, value) VALUES (?, ?) ` , k , val )
}
app . handleGetSettings ( w , r )
}
2026-03-03 19:55:35 -06:00
func ( app * App ) handleResetAttendees ( w http . ResponseWriter , r * http . Request ) {
2026-03-03 20:14:56 -06:00
ts := now ( )
result , err := app . db . Exec ( ` UPDATE attendees SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL ` , ts , ts )
2026-03-03 19:55:35 -06:00
if err != nil {
writeError ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
n , _ := result . RowsAffected ( )
writeJSON ( w , map [ string ] any { "deleted" : n } )
}
2026-03-04 10:53:42 -06:00
func ( app * App ) handleResetTickets ( w http . ResponseWriter , r * http . Request ) {
ts := now ( )
result , err := app . db . Exec ( ` UPDATE tickets SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL ` , ts , ts )
if err != nil {
writeError ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
n , _ := result . RowsAffected ( )
writeJSON ( w , map [ string ] any { "deleted" : n } )
}
2026-03-03 19:55:35 -06:00
func ( app * App ) handleResetVolunteers ( w http . ResponseWriter , r * http . Request ) {
2026-03-03 20:14:56 -06:00
ts := now ( )
result , err := app . db . Exec ( ` UPDATE volunteers SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL ` , ts , ts )
2026-03-03 19:55:35 -06:00
if err != nil {
writeError ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
n , _ := result . RowsAffected ( )
writeJSON ( w , map [ string ] any { "deleted" : n } )
}
func ( app * App ) handleResetShifts ( w http . ResponseWriter , r * http . Request ) {
2026-03-03 20:14:56 -06:00
ts := now ( )
result , err := app . db . Exec ( ` UPDATE shifts SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL ` , ts , ts )
2026-03-03 19:55:35 -06:00
if err != nil {
writeError ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
n , _ := result . RowsAffected ( )
2026-03-03 20:14:56 -06:00
// Also soft-delete orphaned volunteer_shifts
app . db . Exec ( ` UPDATE volunteer_shifts SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL AND shift_id IN (SELECT id FROM shifts WHERE deleted_at IS NOT NULL) ` , ts , ts )
2026-03-03 19:55:35 -06:00
writeJSON ( w , map [ string ] any { "deleted" : n } )
}
func ( app * App ) handleResetDepartments ( w http . ResponseWriter , r * http . Request ) {
2026-03-03 20:14:56 -06:00
ts := now ( )
// Soft-delete shifts in these departments first (so sync picks them up)
app . db . Exec ( ` UPDATE volunteer_shifts SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL AND shift_id IN (SELECT id FROM shifts WHERE department_id IN (SELECT id FROM departments WHERE deleted_at IS NULL)) ` , ts , ts )
app . db . Exec ( ` UPDATE shifts SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL AND department_id IN (SELECT id FROM departments WHERE deleted_at IS NULL) ` , ts , ts )
result , err := app . db . Exec ( ` UPDATE departments SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL ` , ts , ts )
2026-03-03 19:55:35 -06:00
if err != nil {
writeError ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
n , _ := result . RowsAffected ( )
writeJSON ( w , map [ string ] any { "deleted" : n } )
}
func ( app * App ) handleResetVolunteerShifts ( w http . ResponseWriter , r * http . Request ) {
2026-03-03 20:14:56 -06:00
ts := now ( )
result , err := app . db . Exec ( ` UPDATE volunteer_shifts SET deleted_at=?, updated_at=? WHERE deleted_at IS NULL ` , ts , ts )
2026-03-03 19:55:35 -06:00
if err != nil {
writeError ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
n , _ := result . RowsAffected ( )
writeJSON ( w , map [ string ] any { "deleted" : n } )
}
2026-03-03 11:27:07 -06:00
func ( app * App ) handleTestEmail ( w http . ResponseWriter , r * http . Request ) {
var body struct {
To string ` json:"to" `
}
if err := json . NewDecoder ( r . Body ) . Decode ( & body ) ; err != nil || body . To == "" {
writeError ( w , "to email address required" , http . StatusBadRequest )
return
}
cfg := app . loadSMTPConfig ( )
if err := sendEmail ( cfg , body . To , "Turnpike test email" , "This is a test email from your Turnpike instance. SMTP is configured correctly." ) ; err != nil {
writeError ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
writeJSON ( w , map [ string ] any { "ok" : true } )
}