Files
soft_usite/rest/controllers/hostinger_controller.go
T

387 lines
14 KiB
Go

package controllers
import (
"time"
"github.com/gofiber/fiber/v2"
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
)
// ─── Configuración ────────────────────────────────────────────────────────────
// HostingerConfigPage renderiza la vista de gestión de Hostinger.
func HostingerConfigPage(c *fiber.Ctx) error {
cfg, _ := models.GetHostingerConfig()
if err := c.Render("hostinger", fiber.Map{
"Title": "Hostinger API",
"Config": cfg,
"user": c.Locals("user"),
"modules": c.Locals("userModules"),
}, "layouts/main"); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return nil
}
// SaveHostingerConfig guarda o actualiza el token de Hostinger.
func SaveHostingerConfig(c *fiber.Ctx) error {
type body struct {
ID uint `json:"id" form:"id"`
Token string `json:"token" form:"token"`
Nota string `json:"nota" form:"nota"`
}
var b body
if err := c.BodyParser(&b); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"})
}
if b.Token == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "token requerido"})
}
cfg := models.HostingerConfig{
Nota: b.Nota,
Token: b.Token,
}
cfg.ID = b.ID
if err := models.SaveHostingerConfig(cfg); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Configuración guardada"})
}
// ─── Helpers ─────────────────────────────────────────────────────────────────
func hostingerClient() (*services.HostingerClient, error) {
cfg, err := models.GetHostingerConfig()
if err != nil {
return nil, err
}
return services.NewHostingerClient(cfg.Token), nil
}
// ─── Endpoints de datos ───────────────────────────────────────────────────────
// GetHostingerVPS devuelve la lista de VPS/VMs.
func GetHostingerVPS(c *fiber.Ctx) error {
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{
"error": "No se encontró configuración activa de Hostinger",
})
}
data, err := client.GetVPSList()
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": data})
}
// GetHostingerDomains devuelve el portafolio de dominios.
func GetHostingerDomains(c *fiber.Ctx) error {
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{
"error": "No se encontró configuración activa de Hostinger",
})
}
data, err := client.GetDomains()
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": data})
}
// GetHostingerDNS devuelve los registros DNS y los nameservers de un dominio (:domain).
func GetHostingerDNS(c *fiber.Ctx) error {
domain := c.Params("domain")
if domain == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "dominio requerido"})
}
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{
"error": "No se encontró configuración activa de Hostinger",
})
}
records, err := client.GetDNSRecords(domain)
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
// Nameservers son opcionales: si falla (ej. VPS hostnames no están en portafolio) se ignora.
ns, _ := client.GetDomainNameServers(domain)
return c.JSON(fiber.Map{"data": records, "name_servers": ns, "domain": domain})
}
// GetHostingerOrders devuelve las órdenes de facturación.
func GetHostingerOrders(c *fiber.Ctx) error {
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{
"error": "No se encontró configuración activa de Hostinger",
})
}
data, err := client.GetOrders()
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": data})
}
// GetHostingerHosting devuelve las cuentas de hosting.
func GetHostingerHosting(c *fiber.Ctx) error {
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{
"error": "No se encontró configuración activa de Hostinger",
})
}
data, err := client.GetHostingAccounts()
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": data})
}
// ─── DNS: escritura ──────────────────────────────────────────────────────────
// UpdateHostingerDNS agrega o actualiza registros DNS.
func UpdateHostingerDNS(c *fiber.Ctx) error {
domain := c.Params("domain")
if domain == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "dominio requerido"})
}
var body struct {
Overwrite bool `json:"overwrite"`
Zone []services.HostingerDNSZoneInput `json:"zone"`
}
if err := c.BodyParser(&body); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"})
}
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
if err := client.UpdateDNSZone(domain, body.Overwrite, body.Zone); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "DNS actualizado"})
}
// ResetHostingerDNS resetea la zona DNS de un dominio.
func ResetHostingerDNS(c *fiber.Ctx) error {
domain := c.Params("domain")
if domain == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "dominio requerido"})
}
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
if err := client.ResetDNS(domain); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Zona DNS reseteada"})
}
// ─── Domains: escritura ──────────────────────────────────────────────────────
// UpdateHostingerNameservers actualiza los nameservers de un dominio.
func UpdateHostingerNameservers(c *fiber.Ctx) error {
domain := c.Params("domain")
var body struct {
NS1 string `json:"ns1"`
NS2 string `json:"ns2"`
NS3 string `json:"ns3"`
NS4 string `json:"ns4"`
}
if err := c.BodyParser(&body); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"})
}
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
if err := client.UpdateNameservers(domain, body.NS1, body.NS2, body.NS3, body.NS4); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Nameservers actualizados"})
}
// EnableHostingerDomainLock activa el bloqueo del dominio.
func EnableHostingerDomainLock(c *fiber.Ctx) error {
return hostingerDomainToggle(c, "domain-lock", true)
}
// DisableHostingerDomainLock desactiva el bloqueo del dominio.
func DisableHostingerDomainLock(c *fiber.Ctx) error {
return hostingerDomainToggle(c, "domain-lock", false)
}
// EnableHostingerPrivacy activa la protección WHOIS.
func EnableHostingerPrivacy(c *fiber.Ctx) error {
return hostingerDomainToggle(c, "privacy", true)
}
// DisableHostingerPrivacy desactiva la protección WHOIS.
func DisableHostingerPrivacy(c *fiber.Ctx) error {
return hostingerDomainToggle(c, "privacy", false)
}
func hostingerDomainToggle(c *fiber.Ctx, feature string, enable bool) error {
domain := c.Params("domain")
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
var e error
switch feature {
case "domain-lock":
e = client.SetDomainLock(domain, enable)
case "privacy":
e = client.SetPrivacyProtection(domain, enable)
}
if e != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": e.Error()})
}
return c.JSON(fiber.Map{"message": "Operación realizada"})
}
// ─── VPS: acciones ───────────────────────────────────────────────────────────
// StartHostingerVPS arranca una VM.
func StartHostingerVPS(c *fiber.Ctx) error { return vpsAction(c, "start") }
// StopHostingerVPS apaga una VM.
func StopHostingerVPS(c *fiber.Ctx) error { return vpsAction(c, "stop") }
// RestartHostingerVPS reinicia una VM.
func RestartHostingerVPS(c *fiber.Ctx) error { return vpsAction(c, "restart") }
func vpsAction(c *fiber.Ctx, action string) error {
id, err := c.ParamsInt("id")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"})
}
client, errC := hostingerClient()
if errC != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
if err := client.VPSAction(id, action); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": action + " enviado"})
}
// SetHostingerVPSRootPassword cambia la contraseña root de una VM.
func SetHostingerVPSRootPassword(c *fiber.Ctx) error {
id, err := c.ParamsInt("id")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"})
}
var body struct {
Password string `json:"password"`
}
if err := c.BodyParser(&body); err != nil || body.Password == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "password requerido"})
}
client, errC := hostingerClient()
if errC != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
if err := client.SetVPSRootPassword(id, body.Password); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Contraseña actualizada"})
}
// SetHostingerVPSHostname cambia el hostname de una VM.
func SetHostingerVPSHostname(c *fiber.Ctx) error {
id, err := c.ParamsInt("id")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"})
}
var body struct {
Hostname string `json:"hostname"`
}
if err := c.BodyParser(&body); err != nil || body.Hostname == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "hostname requerido"})
}
client, errC := hostingerClient()
if errC != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
if err := client.SetVPSHostname(id, body.Hostname); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Hostname actualizado"})
}
// GetHostingerVPSMetrics retorna las métricas de una VM.
// Acepta query params date_from y date_to (RFC3339). Por defecto: últimas 24 h.
func GetHostingerVPSMetrics(c *fiber.Ctx) error {
id, err := c.ParamsInt("id")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"})
}
client, errC := hostingerClient()
if errC != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
now := time.Now().UTC()
dateFrom := c.Query("date_from", now.Add(-24*time.Hour).Format(time.RFC3339))
dateTo := c.Query("date_to", now.Format(time.RFC3339))
data, err := client.GetVPSMetrics(id, dateFrom, dateTo)
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(data)
}
// GetHostingerVPSBackups retorna los backups de una VM.
func GetHostingerVPSBackups(c *fiber.Ctx) error {
id, err := c.ParamsInt("id")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"})
}
client, errC := hostingerClient()
if errC != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
data, err := client.GetVPSBackups(id)
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(data)
}
// ─── Billing: acciones ───────────────────────────────────────────────────────
// EnableHostingerAutoRenewal activa la autorenovación de una suscripción.
func EnableHostingerAutoRenewal(c *fiber.Ctx) error {
return hostingerAutoRenewalToggle(c, true)
}
// DisableHostingerAutoRenewal desactiva la autorenovación de una suscripción.
func DisableHostingerAutoRenewal(c *fiber.Ctx) error {
return hostingerAutoRenewalToggle(c, false)
}
func hostingerAutoRenewalToggle(c *fiber.Ctx, enable bool) error {
subID := c.Params("id")
if subID == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id requerido"})
}
client, err := hostingerClient()
if err != nil {
return c.Status(fiber.StatusFailedDependency).JSON(fiber.Map{"error": "No se encontró configuración activa de Hostinger"})
}
sub, err := client.ToggleAutoRenewal(subID, enable)
if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": sub})
}