205 lines
5.6 KiB
Go

package server
import (
"encoding/json"
"html"
"html/template"
"net/http"
"strconv"
"git.mziesel.nl/mans/zadmin/internal/formatting"
"git.mziesel.nl/mans/zadmin/internal/models"
)
func (s *Server) registerHttpRoutes() {
s.Router.HandleFunc("GET /health", s.healthCheck)
// {$} means exact match
s.Router.HandleFunc("GET /host", s.hostIndexHandler)
s.Router.HandleFunc("POST /host", s.hostCreateHandler)
s.Router.HandleFunc("GET /host/create", s.hostCreateFormHandler)
// s.Router.HandleFunc("GET /hosts", s.hostIndexHandler)
// s.Router.HandleFunc("GET /hosts/{id}", s.hostHandler)
s.Router.HandleFunc("GET /api/v1/host", s.getAllHosts)
s.Router.HandleFunc("POST /api/v1/host", s.createHost)
s.Router.HandleFunc("GET /api/v1/host/{id}", s.getHost)
s.Router.HandleFunc("PUT /api/v1/host/{id}", s.updateHost)
s.Router.HandleFunc("DELETE /api/v1/host/{id}", s.deleteHost)
}
func (s *Server) hostIndexHandler(w http.ResponseWriter, r *http.Request) {
t := template.Must(template.ParseFiles("templates/layout.html", "templates/host/index.html"))
var hosts []models.Host
s.DB.Find(&hosts)
err := t.Execute(w, hosts)
if err != nil {
s.Logger.Error(err)
}
}
func (s *Server) hostCreateHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
s.Logger.Info("request to create host")
h_name := html.UnescapeString(r.PostFormValue("name"))
h_desc := html.UnescapeString(r.PostFormValue("description"))
h_os_type := html.UnescapeString(r.PostFormValue("os_type"))
h_os_arch := html.UnescapeString(r.PostFormValue("os_arch"))
host := models.Host{
Name: h_name,
Description: &h_desc,
OsType: models.OsType(h_os_type),
OsArch: &h_os_arch,
}
res := s.DB.Create(&host)
if res.RowsAffected != 0 {
s.Logger.Error("failed to create host, RowsAffected is 0")
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(host)
t := template.Must(template.ParseFiles("templates/host/create.html"))
err := t.Execute(w, nil)
if err != nil {
s.Logger.Error(err)
}
}
func (s *Server) hostCreateFormHandler(w http.ResponseWriter, r *http.Request) {
t := template.Must(template.ParseFiles("templates/layout.html", "templates/host/create.html"))
err := t.Execute(w, nil)
if err != nil {
s.Logger.Error(err)
}
}
func (s *Server) healthCheck(w http.ResponseWriter, r *http.Request) {
s.Logger.Debug("Health check endpoint hit")
err := s.DB.Exec("SELECT 1").Error
if err != nil {
s.Logger.Error("Can not establish connection to database")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Can not establish connection to database"))
return
}
ns := s.NATS.Status()
if ns.String() != "CONNECTED" {
w.WriteHeader(http.StatusInternalServerError)
s.Logger.Error("Can not establish connection to NATS")
w.Write([]byte("Can not establish connection to NATS"))
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
func (s *Server) getAllHosts(w http.ResponseWriter, r *http.Request) {
var host []models.Host
res := s.DB.Find(&host)
if res.Error != nil {
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(formatting.PrettyFormatData(host)))
}
func (s *Server) getHost(w http.ResponseWriter, r *http.Request) {
hostIdString := r.PathValue("id")
hostID, err := strconv.Atoi(hostIdString)
if err != nil {
s.Logger.Error(err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
var host models.Host
res := s.DB.Where("id = ?", hostID).First(&host)
if res.Error != nil {
http.Error(w, res.Error.Error(), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(formatting.PrettyFormatData(host)))
}
func (s *Server) createHost(w http.ResponseWriter, r *http.Request) {
var host models.Host
if err := json.NewDecoder(r.Body).Decode(&host); err != nil {
http.Error(w, "Invalid input", http.StatusBadRequest)
return
}
// only allow certain fields
s.DB.Select("name", "description", "os_type", "os_arch").Create(&host)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(host)
}
func (s *Server) deleteHost(w http.ResponseWriter, r *http.Request) {
hostIdString := r.PathValue("id")
hostID, err := strconv.Atoi(hostIdString)
if err != nil {
s.Logger.Error(err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
var host models.Host
res := s.DB.Where("id = ?", hostID).First(&host)
if res.Error != nil {
http.NotFound(w, r)
return
}
// delete stats
s.DB.Delete(&models.HostStatistics{}, "host_id = ?", host.ID)
// delete host
s.DB.Delete(&models.Host{}, host.ID)
w.WriteHeader(http.StatusNoContent)
}
func (s *Server) updateHost(w http.ResponseWriter, r *http.Request) {
var updatedHost models.Host
if err := json.NewDecoder(r.Body).Decode(&updatedHost); err != nil {
http.Error(w, "Invalid input", http.StatusBadRequest)
return
}
hostIdString := r.PathValue("id")
hostID, err := strconv.Atoi(hostIdString)
if err != nil {
s.Logger.Error(err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
var host models.Host
res := s.DB.Where("id = ?", hostID).First(&host)
if res.Error != nil {
http.Error(w, res.Error.Error(), http.StatusInternalServerError)
return
}
if host.ID == 0 {
http.NotFound(w, r)
return
}
// only allow certain fields
s.DB.Model(&host).Select("name", "description", "os_type", "os_arch").Updates(updatedHost)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(host)
}