package server import ( "encoding/json" "errors" "net/http" "github.com/go-chi/chi/v5" "git.wntrmute.dev/mc/mcns/internal/db" ) type createZoneRequest struct { Name string `json:"name"` PrimaryNS string `json:"primary_ns"` AdminEmail string `json:"admin_email"` Refresh int `json:"refresh"` Retry int `json:"retry"` Expire int `json:"expire"` MinimumTTL int `json:"minimum_ttl"` } func listZonesHandler(database *db.DB) http.HandlerFunc { return func(w http.ResponseWriter, _ *http.Request) { zones, err := database.ListZones() if err != nil { writeError(w, http.StatusInternalServerError, "failed to list zones") return } if zones == nil { zones = []db.Zone{} } writeJSON(w, http.StatusOK, map[string]any{"zones": zones}) } } func getZoneHandler(database *db.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := chi.URLParam(r, "zone") zone, err := database.GetZone(name) if errors.Is(err, db.ErrNotFound) { writeError(w, http.StatusNotFound, "zone not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to get zone") return } writeJSON(w, http.StatusOK, zone) } } func createZoneHandler(database *db.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req createZoneRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if req.Name == "" { writeError(w, http.StatusBadRequest, "name is required") return } if req.PrimaryNS == "" { writeError(w, http.StatusBadRequest, "primary_ns is required") return } if req.AdminEmail == "" { writeError(w, http.StatusBadRequest, "admin_email is required") return } // Apply defaults for SOA params. req.Refresh, req.Retry, req.Expire, req.MinimumTTL = db.ApplySOADefaults(req.Refresh, req.Retry, req.Expire, req.MinimumTTL) zone, err := database.CreateZone(req.Name, req.PrimaryNS, req.AdminEmail, req.Refresh, req.Retry, req.Expire, req.MinimumTTL) if errors.Is(err, db.ErrConflict) { writeError(w, http.StatusConflict, err.Error()) return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to create zone") return } writeJSON(w, http.StatusCreated, zone) } } func updateZoneHandler(database *db.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := chi.URLParam(r, "zone") var req createZoneRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if req.PrimaryNS == "" { writeError(w, http.StatusBadRequest, "primary_ns is required") return } if req.AdminEmail == "" { writeError(w, http.StatusBadRequest, "admin_email is required") return } req.Refresh, req.Retry, req.Expire, req.MinimumTTL = db.ApplySOADefaults(req.Refresh, req.Retry, req.Expire, req.MinimumTTL) zone, err := database.UpdateZone(name, req.PrimaryNS, req.AdminEmail, req.Refresh, req.Retry, req.Expire, req.MinimumTTL) if errors.Is(err, db.ErrNotFound) { writeError(w, http.StatusNotFound, "zone not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to update zone") return } writeJSON(w, http.StatusOK, zone) } } func deleteZoneHandler(database *db.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := chi.URLParam(r, "zone") err := database.DeleteZone(name) if errors.Is(err, db.ErrNotFound) { writeError(w, http.StatusNotFound, "zone not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to delete zone") return } w.WriteHeader(http.StatusNoContent) } }