package auth import ( "encoding/json" "net/http" "time" "git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware" "github.com/go-chi/chi/v5" ) type availabilitySlot struct { DayOfWeek string `json:"day_of_week"` StartTime string `json:"start_time"` // HH:MM EndTime string `json:"end_time"` // HH:MM } func (h *Handler) GetMyAvailability(w http.ResponseWriter, r *http.Request) { userID, ok := middleware.UserIDFromContext(r.Context()) if !ok { http.Error(w, "unauthorized", http.StatusUnauthorized) return } serverID := r.URL.Query().Get("server_id") if serverID == "" { http.Error(w, "server_id query param required", http.StatusBadRequest) return } rows, err := h.db.Query( `SELECT day_of_week, start_time, end_time FROM availability WHERE user_id = $1 AND server_id = $2 ORDER BY array_position(ARRAY['monday','tuesday','wednesday','thursday','friday','saturday','sunday'], day_of_week), start_time`, userID, serverID, ) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() var slots []availabilitySlot for rows.Next() { var s availabilitySlot var st, et time.Time if err := rows.Scan(&s.DayOfWeek, &st, &et); err != nil { continue } s.StartTime = st.Format("15:04") s.EndTime = et.Format("15:04") slots = append(slots, s) } if slots == nil { slots = []availabilitySlot{} } json.NewEncoder(w).Encode(slots) } func (h *Handler) PutMyAvailability(w http.ResponseWriter, r *http.Request) { userID, ok := middleware.UserIDFromContext(r.Context()) if !ok { http.Error(w, "unauthorized", http.StatusUnauthorized) return } serverID := r.URL.Query().Get("server_id") if serverID == "" { http.Error(w, "server_id query param required", http.StatusBadRequest) return } var slots []availabilitySlot if err := json.NewDecoder(r.Body).Decode(&slots); err != nil { http.Error(w, "invalid json", http.StatusBadRequest) return } tx, err := h.db.Begin() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer tx.Rollback() if _, err := tx.Exec(`DELETE FROM availability WHERE user_id = $1 AND server_id = $2`, userID, serverID); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } for _, s := range slots { _, err := tx.Exec( `INSERT INTO availability (user_id, server_id, day_of_week, start_time, end_time) VALUES ($1,$2,$3,$4::time,$5::time)`, userID, serverID, s.DayOfWeek, s.StartTime, s.EndTime, ) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } if err := tx.Commit(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(slots) } // GetServerAvailability returns all members' availability for a server, aggregated by user. func (h *Handler) GetServerAvailability(w http.ResponseWriter, r *http.Request) { serverID := chi.URLParam(r, "serverID") rows, err := h.db.Query( `SELECT a.user_id, u.display_name, a.day_of_week, a.start_time, a.end_time FROM availability a JOIN users u ON u.id = a.user_id WHERE a.server_id = $1 ORDER BY u.display_name, array_position(ARRAY['monday','tuesday','wednesday','thursday','friday','saturday','sunday'], a.day_of_week), a.start_time`, serverID, ) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() type slot struct { DayOfWeek string `json:"day_of_week"` StartTime string `json:"start_time"` EndTime string `json:"end_time"` } type userAvail struct { UserID string `json:"user_id"` Username string `json:"username"` Slots []slot `json:"slots"` } userMap := make(map[string]*userAvail) for rows.Next() { var uid, uname, dow string var st, et time.Time if err := rows.Scan(&uid, &uname, &dow, &st, &et); err != nil { continue } ua, ok := userMap[uid] if !ok { ua = &userAvail{UserID: uid, Username: uname} userMap[uid] = ua } ua.Slots = append(ua.Slots, slot{DayOfWeek: dow, StartTime: st.Format("15:04"), EndTime: et.Format("15:04")}) } result := make([]userAvail, 0, len(userMap)) for _, ua := range userMap { result = append(result, *ua) } if result == nil { result = []userAvail{} } json.NewEncoder(w).Encode(result) }