213 lines
5.0 KiB
Go
213 lines
5.0 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"lostcavewireplanner/internal/models"
|
|
)
|
|
|
|
type ModelListData struct {
|
|
Models []models.DeviceModel
|
|
Error string
|
|
}
|
|
|
|
type ModelFormData struct {
|
|
Model *models.DeviceModel
|
|
Error string
|
|
IsEdit bool
|
|
}
|
|
|
|
func (h *Handlers) ModelList(w http.ResponseWriter, r *http.Request) {
|
|
list, _ := h.Store.ModelGetAll()
|
|
if list == nil {
|
|
list = []models.DeviceModel{}
|
|
}
|
|
h.render(w, "model_list.html", ModelListData{Models: list})
|
|
}
|
|
|
|
func (h *Handlers) ModelCreateForm(w http.ResponseWriter, r *http.Request) {
|
|
h.render(w, "model_form.html", ModelFormData{IsEdit: false})
|
|
}
|
|
|
|
func (h *Handlers) ModelEditForm(w http.ResponseWriter, r *http.Request) {
|
|
idStr := r.PathValue("id")
|
|
id, _ := strconv.ParseInt(idStr, 10, 64)
|
|
|
|
model, err := h.Store.ModelGetByID(id)
|
|
if err != nil || model == nil {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
h.render(w, "model_form.html", ModelFormData{Model: model, IsEdit: true})
|
|
}
|
|
|
|
func (h *Handlers) ModelCreate(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseMultipartForm(10 << 20); err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
m := &models.DeviceModel{
|
|
Name: r.FormValue("name"),
|
|
Manufacturer: r.FormValue("manufacturer"),
|
|
IsPatchPanel: r.FormValue("is_patch_panel") == "on",
|
|
IsWallSocket: r.FormValue("is_wall_socket") == "on",
|
|
IsPowerStrip: r.FormValue("is_power_strip") == "on",
|
|
}
|
|
|
|
isRack := r.FormValue("is_rack_mountable") == "on"
|
|
m.IsRackMountable = isRack
|
|
if isRack {
|
|
if huStr := r.FormValue("height_units"); huStr != "" {
|
|
hu, _ := strconv.Atoi(huStr)
|
|
m.HeightUnits = &hu
|
|
}
|
|
}
|
|
|
|
m.FrontImage = saveUploadedFile(r, "front_image", "uploads")
|
|
m.BackImage = saveUploadedFile(r, "back_image", "uploads")
|
|
|
|
parsePortsFromForm(r, m)
|
|
|
|
if m.Name == "" {
|
|
h.render(w, "model_form.html", ModelFormData{Model: m, IsEdit: false, Error: "Name is required"})
|
|
return
|
|
}
|
|
|
|
_, err := h.Store.ModelCreate(m, "uploads")
|
|
if err != nil {
|
|
h.render(w, "model_form.html", ModelFormData{Model: m, IsEdit: false, Error: err.Error()})
|
|
return
|
|
}
|
|
|
|
http.Redirect(w, r, "/models", http.StatusSeeOther)
|
|
}
|
|
|
|
func (h *Handlers) ModelUpdate(w http.ResponseWriter, r *http.Request) {
|
|
idStr := r.PathValue("id")
|
|
id, _ := strconv.ParseInt(idStr, 10, 64)
|
|
|
|
if err := r.ParseMultipartForm(10 << 20); err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
m, err := h.Store.ModelGetByID(id)
|
|
if err != nil || m == nil {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
m.Name = r.FormValue("name")
|
|
m.Manufacturer = r.FormValue("manufacturer")
|
|
m.IsPatchPanel = r.FormValue("is_patch_panel") == "on"
|
|
m.IsWallSocket = r.FormValue("is_wall_socket") == "on"
|
|
m.IsPowerStrip = r.FormValue("is_power_strip") == "on"
|
|
|
|
isRack := r.FormValue("is_rack_mountable") == "on"
|
|
m.IsRackMountable = isRack
|
|
if isRack {
|
|
if huStr := r.FormValue("height_units"); huStr != "" {
|
|
hu, _ := strconv.Atoi(huStr)
|
|
m.HeightUnits = &hu
|
|
}
|
|
} else {
|
|
m.HeightUnits = nil
|
|
}
|
|
|
|
if frontImg := saveUploadedFile(r, "front_image", "uploads"); frontImg != "" {
|
|
m.FrontImage = frontImg
|
|
}
|
|
if backImg := saveUploadedFile(r, "back_image", "uploads"); backImg != "" {
|
|
m.BackImage = backImg
|
|
}
|
|
|
|
parsePortsFromForm(r, m)
|
|
|
|
if m.Name == "" {
|
|
h.render(w, "model_form.html", ModelFormData{Model: m, IsEdit: true, Error: "Name is required"})
|
|
return
|
|
}
|
|
|
|
if err := h.Store.ModelUpdate(m); err != nil {
|
|
h.render(w, "model_form.html", ModelFormData{Model: m, IsEdit: true, Error: err.Error()})
|
|
return
|
|
}
|
|
|
|
http.Redirect(w, r, "/models", http.StatusSeeOther)
|
|
}
|
|
|
|
func (h *Handlers) ModelDelete(w http.ResponseWriter, r *http.Request) {
|
|
idStr := r.PathValue("id")
|
|
id, _ := strconv.ParseInt(idStr, 10, 64)
|
|
if err := h.Store.ModelDelete(id); err != nil {
|
|
h.renderModelListError(w, "Cannot delete model: it is in use by existing devices.")
|
|
return
|
|
}
|
|
http.Redirect(w, r, "/models", http.StatusSeeOther)
|
|
}
|
|
|
|
func (h *Handlers) renderModelListError(w http.ResponseWriter, msg string) {
|
|
list, _ := h.Store.ModelGetAll()
|
|
if list == nil {
|
|
list = []models.DeviceModel{}
|
|
}
|
|
h.render(w, "model_list.html", ModelListData{Models: list, Error: msg})
|
|
}
|
|
|
|
func saveUploadedFile(r *http.Request, field, dir string) string {
|
|
file, header, err := r.FormFile(field)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
defer file.Close()
|
|
|
|
ext := ""
|
|
if idx := strings.LastIndex(header.Filename, "."); idx >= 0 {
|
|
ext = header.Filename[idx:]
|
|
}
|
|
|
|
safeName := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
|
|
fpath := filepath.Join(dir, safeName)
|
|
|
|
dst, err := os.Create(fpath)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
defer dst.Close()
|
|
|
|
if _, err := io.Copy(dst, file); err != nil {
|
|
return ""
|
|
}
|
|
return fpath
|
|
}
|
|
|
|
func parsePortsFromForm(r *http.Request, m *models.DeviceModel) {
|
|
r.ParseForm()
|
|
portNames := r.Form["port_name"]
|
|
portSides := r.Form["port_side"]
|
|
|
|
m.Ports = nil
|
|
for i := range portNames {
|
|
if i >= len(portSides) {
|
|
break
|
|
}
|
|
if portNames[i] == "" {
|
|
continue
|
|
}
|
|
m.Ports = append(m.Ports, models.DeviceModelPort{
|
|
Name: portNames[i],
|
|
Side: portSides[i],
|
|
Position: i,
|
|
})
|
|
}
|
|
}
|