2025-06-22 21:59:09 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"database/sql"
|
2025-06-26 16:16:33 +02:00
|
|
|
"encoding/base64"
|
2025-06-22 21:59:09 +02:00
|
|
|
"fmt"
|
2025-06-26 16:16:33 +02:00
|
|
|
"log"
|
2025-06-22 21:59:09 +02:00
|
|
|
"net/http"
|
2025-06-26 13:05:59 +02:00
|
|
|
"os"
|
2025-06-26 15:54:43 +02:00
|
|
|
"strconv"
|
2025-06-26 16:16:33 +02:00
|
|
|
"strings"
|
2025-06-22 21:59:09 +02:00
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2025-06-26 16:16:33 +02:00
|
|
|
var token string
|
|
|
|
|
|
2025-06-22 21:59:09 +02:00
|
|
|
type Handler struct {
|
|
|
|
|
db *sql.DB
|
|
|
|
|
ntfy *Ntfy
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-26 13:05:59 +02:00
|
|
|
func getStaticFile(relPath string, contentType string, w http.ResponseWriter) {
|
|
|
|
|
file, err := os.ReadFile(relPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
fmt.Fprintf(w, "%s", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w.Header().Add("Content-Type", contentType)
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
w.Write(file)
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-26 16:16:33 +02:00
|
|
|
func SetupAuth() {
|
|
|
|
|
var username string
|
|
|
|
|
var password string
|
|
|
|
|
for _, entry := range os.Environ() {
|
|
|
|
|
split := strings.Split(entry, "=")
|
|
|
|
|
switch split[0] {
|
|
|
|
|
case "USERNAME":
|
|
|
|
|
username = split[1]
|
|
|
|
|
case "PASSWORD":
|
|
|
|
|
password = split[1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if username != "" && password != "" {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if username == "" || password == "" {
|
|
|
|
|
log.Fatal("no authorization details")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sb := new(strings.Builder)
|
|
|
|
|
encoder := base64.NewEncoder(base64.StdEncoding, sb)
|
|
|
|
|
encoder.Write(fmt.Appendf(nil, "%s:%s", username, password))
|
|
|
|
|
encoder.Close()
|
|
|
|
|
|
|
|
|
|
token = sb.String()
|
2025-06-27 16:34:33 +02:00
|
|
|
|
|
|
|
|
fmt.Println("auth ready")
|
2025-06-26 16:16:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func isAuthorized(r *http.Request) bool {
|
|
|
|
|
auth := r.Header.Get("Authorization")
|
|
|
|
|
|
|
|
|
|
if auth == "" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return auth == token
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 21:59:09 +02:00
|
|
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
fmt.Printf("%s - [%s] (%s) %s\n", time.Now().Format(time.RFC3339), r.RemoteAddr, r.Method, r.URL)
|
|
|
|
|
|
|
|
|
|
switch true {
|
|
|
|
|
case r.Method == "GET" && r.URL.Path == "/":
|
2025-06-29 10:17:33 +02:00
|
|
|
getStaticFile("./client/index.html", "text/html", w)
|
2025-06-26 13:05:59 +02:00
|
|
|
|
|
|
|
|
case r.Method == "GET" && r.URL.Path == "/rsvp":
|
2025-06-29 10:17:33 +02:00
|
|
|
getStaticFile("./client/rsvp.html", "text/html", w)
|
2025-06-26 13:05:59 +02:00
|
|
|
|
2025-06-26 15:54:43 +02:00
|
|
|
case r.Method == "GET" && r.URL.Path == "/rsvp_confirmed":
|
2025-06-29 10:17:33 +02:00
|
|
|
getStaticFile("./client/rsvp_confirmed.html", "text/html", w)
|
2025-06-26 15:54:43 +02:00
|
|
|
|
2025-06-26 13:05:59 +02:00
|
|
|
case r.Method == "GET" && r.URL.Path == "/index.js":
|
2025-06-29 10:17:33 +02:00
|
|
|
getStaticFile("./client/index.js", "text/javascript", w)
|
2025-06-26 13:05:59 +02:00
|
|
|
|
2025-06-26 15:54:43 +02:00
|
|
|
case r.Method == "GET" && r.URL.Path == "/rsvp.js":
|
2025-06-29 10:17:33 +02:00
|
|
|
getStaticFile("./client/rsvp.js", "text/javascript", w)
|
2025-06-26 15:54:43 +02:00
|
|
|
|
2025-06-26 13:05:59 +02:00
|
|
|
case r.Method == "GET" && r.URL.Path == "/style.css":
|
2025-06-29 10:17:33 +02:00
|
|
|
getStaticFile("./client/style.css", "text/css", w)
|
2025-06-26 13:05:59 +02:00
|
|
|
|
|
|
|
|
case r.Method == "GET" && r.URL.Path == "/api/rsvps":
|
2025-06-26 16:16:33 +02:00
|
|
|
if !isAuthorized(r) {
|
|
|
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 21:59:09 +02:00
|
|
|
rsvps, err := GetRsvps(h.db)
|
|
|
|
|
if err != nil {
|
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
fmt.Fprintf(w, "%s", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
fmt.Fprintf(w, "%#v", rsvps)
|
2025-06-26 13:05:59 +02:00
|
|
|
|
|
|
|
|
case r.Method == "POST" && r.URL.Path == "/api/rsvps":
|
2025-06-26 15:54:43 +02:00
|
|
|
err := r.ParseForm()
|
2025-06-22 21:59:09 +02:00
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
2025-06-27 16:34:33 +02:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2025-06-22 21:59:09 +02:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-26 15:54:43 +02:00
|
|
|
attending := r.Form.Get("attending") == "true"
|
|
|
|
|
partySize, err := strconv.ParseInt(r.Form.Get("party-size"), 10, 1)
|
|
|
|
|
|
2025-06-27 16:34:33 +02:00
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-26 15:54:43 +02:00
|
|
|
partyMembers := make([]Member, partySize)
|
|
|
|
|
for i := range partySize {
|
|
|
|
|
name := r.Form.Get(fmt.Sprintf("name-%d", i))
|
|
|
|
|
child := r.Form.Has(fmt.Sprintf("child-%d", i)) && r.Form.Get(fmt.Sprintf("child-%d", i)) == "true"
|
|
|
|
|
dietaryPreferences := r.Form.Get(fmt.Sprintf("diet-%d", i))
|
|
|
|
|
member := Member{
|
|
|
|
|
Name: name,
|
|
|
|
|
Child: child,
|
|
|
|
|
DietaryPreferences: dietaryPreferences,
|
|
|
|
|
}
|
|
|
|
|
partyMembers[i] = member
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsvp := Rsvp{
|
|
|
|
|
Attending: attending,
|
|
|
|
|
PartySize: partySize,
|
|
|
|
|
PartyMembers: partyMembers,
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-22 21:59:09 +02:00
|
|
|
_, err = rsvp.CreateRsvp(h.db)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if h.ntfy != nil {
|
|
|
|
|
SendRsvpNotification(h.ntfy, &rsvp)
|
|
|
|
|
}
|
2025-06-26 15:54:43 +02:00
|
|
|
w.Header().Add("Location", "/rsvp_confirmed")
|
|
|
|
|
w.WriteHeader(http.StatusSeeOther)
|
2025-06-22 21:59:09 +02:00
|
|
|
default:
|
|
|
|
|
w.WriteHeader(http.StatusNotFound)
|
|
|
|
|
}
|
|
|
|
|
}
|