routes.go

93 lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
package controllers

import (
	"fmt"
	"net/http"
	"strconv"

	"congo.gg/pkg/application"
	"congo.gg/dev/models"
)

func Routes() (string, *RoutesController) {
	return "routes", &RoutesController{}
}

type RoutesController struct {
	application.BaseController
}

func (c *RoutesController) Setup(app *application.App) {
	c.BaseController.Setup(app)

	// POST handlers — called from dashboard routes panel via HTMX
	http.Handle("POST /routes/add", app.Method(c, "AddRoute", RequireAuth()))
	http.Handle("POST /routes/{id}/delete", app.Method(c, "DeleteRoute", RequireAuth()))
}

func (c RoutesController) Handle(r *http.Request) application.Controller {
	c.Request = r
	return &c
}

// Handlers

func (c *RoutesController) AddRoute(w http.ResponseWriter, r *http.Request) {
	host := r.FormValue("host")
	target := r.FormValue("target")
	portStr := r.FormValue("port")

	if host == "" || target == "" || portStr == "" {
		c.RenderError(w, r, fmt.Errorf("host, target, and port are required"))
		return
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		c.RenderError(w, r, fmt.Errorf("invalid port number"))
		return
	}

	existing, _ := models.Domains.First("WHERE Host = ?", host)
	if existing != nil {
		c.RenderError(w, r, fmt.Errorf("route for %s already exists", host))
		return
	}

	domain := &models.Domain{
		Host:   host,
		Target: target,
		Port:   port,
		Active: true,
	}
	if _, err := models.Domains.Insert(domain); err != nil {
		c.RenderError(w, r, err)
		return
	}

	models.Activities.Insert(&models.Activity{
		Action: "add_route",
		Detail: fmt.Sprintf("Added route %s -> %s:%d", host, target, port),
	})
	c.Refresh(w, r)
}

func (c *RoutesController) DeleteRoute(w http.ResponseWriter, r *http.Request) {
	domain, err := models.Domains.Get(r.PathValue("id"))
	if err != nil {
		c.RenderError(w, r, err)
		return
	}
	if domain.System {
		c.RenderError(w, r, fmt.Errorf("cannot delete system route"))
		return
	}

	models.Domains.Delete(domain)

	models.Activities.Insert(&models.Activity{
		Action: "delete_route",
		Detail: fmt.Sprintf("Removed route %s", domain.Host),
	})
	c.Refresh(w, r)
}