feat: integración Hostinger + Cloudflare API (modelo, servicio, controlador, rutas, migración)
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
||||
)
|
||||
|
||||
// ─── Configuración ────────────────────────────────────────────────────────────
|
||||
|
||||
// CloudflareConfigPage renderiza la vista de gestión de Cloudflare.
|
||||
func CloudflareConfigPage(c *fiber.Ctx) error {
|
||||
cfg, _ := models.GetCloudflareConfig()
|
||||
return c.Render("cloudflare", fiber.Map{
|
||||
"Title": "Cloudflare API",
|
||||
"Config": cfg,
|
||||
})
|
||||
}
|
||||
|
||||
// SaveCloudflareConfig guarda o actualiza el API token de Cloudflare.
|
||||
func SaveCloudflareConfig(c *fiber.Ctx) error {
|
||||
type body struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
APIToken string `json:"api_token" form:"api_token"`
|
||||
AccountID string `json:"account_id" form:"account_id"`
|
||||
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.APIToken == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "api_token requerido"})
|
||||
}
|
||||
|
||||
cfg := models.CloudflareConfig{
|
||||
APIToken: b.APIToken,
|
||||
AccountID: b.AccountID,
|
||||
Nota: b.Nota,
|
||||
}
|
||||
cfg.ID = b.ID
|
||||
|
||||
if err := models.SaveCloudflareConfig(cfg); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"message": "Configuración guardada"})
|
||||
}
|
||||
|
||||
// ─── Helper ───────────────────────────────────────────────────────────────────
|
||||
|
||||
func cloudflareClient() (*services.CloudflareClient, error) {
|
||||
cfg, err := models.GetCloudflareConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return services.NewCloudflareClient(cfg.APIToken, cfg.AccountID), nil
|
||||
}
|
||||
|
||||
// ─── Endpoints de datos ───────────────────────────────────────────────────────
|
||||
|
||||
// GetCloudflareUser devuelve la información del usuario autenticado en Cloudflare.
|
||||
func GetCloudflareUser(c *fiber.Ctx) error {
|
||||
client, err := cloudflareClient()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Cloudflare",
|
||||
})
|
||||
}
|
||||
data, err := client.GetUser()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data})
|
||||
}
|
||||
|
||||
// GetCloudflareZones lista todas las zonas (dominios) de la cuenta.
|
||||
func GetCloudflareZones(c *fiber.Ctx) error {
|
||||
client, err := cloudflareClient()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Cloudflare",
|
||||
})
|
||||
}
|
||||
data, err := client.GetZones()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data})
|
||||
}
|
||||
|
||||
// GetCloudflareDNS devuelve los registros DNS de una zona (:zone_id).
|
||||
func GetCloudflareDNS(c *fiber.Ctx) error {
|
||||
zoneID := c.Params("zone_id")
|
||||
if zoneID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "zone_id requerido"})
|
||||
}
|
||||
client, err := cloudflareClient()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Cloudflare",
|
||||
})
|
||||
}
|
||||
data, err := client.GetDNSRecords(zoneID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data, "zone_id": zoneID})
|
||||
}
|
||||
|
||||
// GetCloudflareSSL devuelve los certificados SSL de una zona (:zone_id).
|
||||
func GetCloudflareSSL(c *fiber.Ctx) error {
|
||||
zoneID := c.Params("zone_id")
|
||||
if zoneID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "zone_id requerido"})
|
||||
}
|
||||
client, err := cloudflareClient()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Cloudflare",
|
||||
})
|
||||
}
|
||||
data, err := client.GetSSLCertificates(zoneID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data, "zone_id": zoneID})
|
||||
}
|
||||
|
||||
// GetCloudflareFirewall devuelve las reglas de firewall de una zona (:zone_id).
|
||||
func GetCloudflareFirewall(c *fiber.Ctx) error {
|
||||
zoneID := c.Params("zone_id")
|
||||
if zoneID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "zone_id requerido"})
|
||||
}
|
||||
client, err := cloudflareClient()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Cloudflare",
|
||||
})
|
||||
}
|
||||
data, err := client.GetFirewallRules(zoneID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data, "zone_id": zoneID})
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"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()
|
||||
return c.Render("hostinger", fiber.Map{
|
||||
"Title": "Hostinger API",
|
||||
"Config": cfg,
|
||||
})
|
||||
}
|
||||
|
||||
// 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.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Hostinger",
|
||||
})
|
||||
}
|
||||
data, err := client.GetVPSList()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).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.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Hostinger",
|
||||
})
|
||||
}
|
||||
data, err := client.GetDomains()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data})
|
||||
}
|
||||
|
||||
// GetHostingerDNS devuelve los registros DNS 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.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Hostinger",
|
||||
})
|
||||
}
|
||||
data, err := client.GetDNSRecords(domain)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data, "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.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Hostinger",
|
||||
})
|
||||
}
|
||||
data, err := client.GetOrders()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).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.StatusServiceUnavailable).JSON(fiber.Map{
|
||||
"error": "No se encontró configuración activa de Hostinger",
|
||||
})
|
||||
}
|
||||
data, err := client.GetHostingAccounts()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": data})
|
||||
}
|
||||
@@ -98,4 +98,22 @@ func UserRoutes(app fiber.Router) {
|
||||
|
||||
// ─── Módulo de Renovaciones / Contratos ──────────────────────────
|
||||
RenovacionesRoutes(protected)
|
||||
|
||||
// ─── Hostinger API ────────────────────────────────────────────────
|
||||
protected.Get("/hostinger", middlewares.MenuMiddleware, controllers.HostingerConfigPage)
|
||||
protected.Post("/hostinger/config", controllers.SaveHostingerConfig)
|
||||
protected.Get("/hostinger/vps", controllers.GetHostingerVPS)
|
||||
protected.Get("/hostinger/domains", controllers.GetHostingerDomains)
|
||||
protected.Get("/hostinger/dns/:domain", controllers.GetHostingerDNS)
|
||||
protected.Get("/hostinger/orders", controllers.GetHostingerOrders)
|
||||
protected.Get("/hostinger/hosting", controllers.GetHostingerHosting)
|
||||
|
||||
// ─── Cloudflare API ───────────────────────────────────────────────
|
||||
protected.Get("/cloudflare", middlewares.MenuMiddleware, controllers.CloudflareConfigPage)
|
||||
protected.Post("/cloudflare/config", controllers.SaveCloudflareConfig)
|
||||
protected.Get("/cloudflare/user", controllers.GetCloudflareUser)
|
||||
protected.Get("/cloudflare/zones", controllers.GetCloudflareZones)
|
||||
protected.Get("/cloudflare/zones/:zone_id/dns", controllers.GetCloudflareDNS)
|
||||
protected.Get("/cloudflare/zones/:zone_id/ssl", controllers.GetCloudflareSSL)
|
||||
protected.Get("/cloudflare/zones/:zone_id/firewall", controllers.GetCloudflareFirewall)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user