package handler import ( "github.com/gofiber/fiber/v2" "github.com/gosec/gsc-ops-api/internal/middleware" "github.com/gosec/gsc-ops-api/internal/service" "github.com/gosec/gsc-ops-api/pkg/types" ) // DNSRecordHandler handles DNS record endpoints type DNSRecordHandler struct { svc *service.DNSService } // NewDNSRecordHandler creates a new DNS record handler func NewDNSRecordHandler(svc *service.DNSService) *DNSRecordHandler { return &DNSRecordHandler{svc: svc} } // List handles GET /api/v1/dns/zones/:zoneId/records func (h *DNSRecordHandler) List(c *fiber.Ctx) error { reqID := middleware.GetRequestID(c) zoneID := c.Params("zoneId") records, err := h.svc.ListRecords(zoneID) if err != nil { apiErr := types.NewInternal(err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } return c.JSON(types.NewDataResponse(records, reqID)) } // Create handles POST /api/v1/dns/zones/:zoneId/records func (h *DNSRecordHandler) Create(c *fiber.Ctx) error { reqID := middleware.GetRequestID(c) zoneID := c.Params("zoneId") var changes []types.DNSRecordChange if err := c.BodyParser(&changes); err != nil { // Try single change var single types.DNSRecordChange if err2 := c.BodyParser(&single); err2 != nil { apiErr := types.NewBadRequest("Invalid request body: " + err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } changes = []types.DNSRecordChange{single} } // Set changetype to REPLACE for creates for i := range changes { if changes[i].ChangeType == "" { changes[i].ChangeType = "REPLACE" } } if err := h.svc.ChangeRecords(zoneID, changes); err != nil { apiErr := types.NewInternal(err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } return c.Status(fiber.StatusCreated).JSON(types.NewDataResponse(fiber.Map{ "zoneId": zoneID, "changes": len(changes), }, reqID)) } // Replace handles PUT /api/v1/dns/zones/:zoneId/records func (h *DNSRecordHandler) Replace(c *fiber.Ctx) error { reqID := middleware.GetRequestID(c) zoneID := c.Params("zoneId") var changes []types.DNSRecordChange if err := c.BodyParser(&changes); err != nil { apiErr := types.NewBadRequest("Invalid request body: " + err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } for i := range changes { changes[i].ChangeType = "REPLACE" } if err := h.svc.ChangeRecords(zoneID, changes); err != nil { apiErr := types.NewInternal(err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } return c.JSON(types.NewDataResponse(fiber.Map{ "zoneId": zoneID, "replaced": len(changes), }, reqID)) } // Delete handles DELETE /api/v1/dns/zones/:zoneId/records func (h *DNSRecordHandler) Delete(c *fiber.Ctx) error { reqID := middleware.GetRequestID(c) zoneID := c.Params("zoneId") var changes []types.DNSRecordChange if err := c.BodyParser(&changes); err != nil { apiErr := types.NewBadRequest("Invalid request body: " + err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } for i := range changes { changes[i].ChangeType = "DELETE" } if err := h.svc.ChangeRecords(zoneID, changes); err != nil { apiErr := types.NewInternal(err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } return c.JSON(types.NewDataResponse(fiber.Map{ "zoneId": zoneID, "deleted": len(changes), }, reqID)) } // DomainSetup handles POST /api/v1/dns/domains/setup func (h *DNSRecordHandler) DomainSetup(c *fiber.Ctx) error { reqID := middleware.GetRequestID(c) var req types.DomainSetup if err := c.BodyParser(&req); err != nil { apiErr := types.NewBadRequest("Invalid request body: " + err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } if req.Domain == "" { apiErr := types.NewValidation("domain is required") return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } zone, err := h.svc.SetupDomain(&req) if err != nil { apiErr := types.NewInternal(err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } return c.Status(fiber.StatusCreated).JSON(types.NewDataResponse(zone, reqID)) } // DomainVerify handles POST /api/v1/dns/domains/verify func (h *DNSRecordHandler) DomainVerify(c *fiber.Ctx) error { reqID := middleware.GetRequestID(c) var req types.DomainVerify if err := c.BodyParser(&req); err != nil { apiErr := types.NewBadRequest("Invalid request body: " + err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } if req.Domain == "" { apiErr := types.NewValidation("domain is required") return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } result, err := h.svc.VerifyDomain(req.Domain) if err != nil { apiErr := types.NewInternal(err.Error()) return c.Status(apiErr.Status).JSON(types.NewErrorResponse(apiErr, reqID)) } return c.JSON(types.NewDataResponse(result, reqID)) }