package backup import ( "fmt" "net/http" "github.com/atlasos/calypso/internal/common/logger" "github.com/gin-gonic/gin" ) // Handler handles backup-related API requests type Handler struct { service *Service logger *logger.Logger } // NewHandler creates a new backup handler func NewHandler(service *Service, log *logger.Logger) *Handler { return &Handler{ service: service, logger: log, } } // ListJobs lists backup jobs with optional filters func (h *Handler) ListJobs(c *gin.Context) { opts := ListJobsOptions{ Status: c.Query("status"), JobType: c.Query("job_type"), ClientName: c.Query("client_name"), JobName: c.Query("job_name"), } // Parse pagination var limit, offset int if limitStr := c.Query("limit"); limitStr != "" { if _, err := fmt.Sscanf(limitStr, "%d", &limit); err == nil { opts.Limit = limit } } if offsetStr := c.Query("offset"); offsetStr != "" { if _, err := fmt.Sscanf(offsetStr, "%d", &offset); err == nil { opts.Offset = offset } } jobs, totalCount, err := h.service.ListJobs(c.Request.Context(), opts) if err != nil { h.logger.Error("Failed to list jobs", "error", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list jobs"}) return } if jobs == nil { jobs = []Job{} } c.JSON(http.StatusOK, gin.H{ "jobs": jobs, "total": totalCount, "limit": opts.Limit, "offset": opts.Offset, }) } // GetJob retrieves a job by ID func (h *Handler) GetJob(c *gin.Context) { id := c.Param("id") job, err := h.service.GetJob(c.Request.Context(), id) if err != nil { if err.Error() == "job not found" { c.JSON(http.StatusNotFound, gin.H{"error": "job not found"}) return } h.logger.Error("Failed to get job", "error", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get job"}) return } c.JSON(http.StatusOK, job) } // CreateJob creates a new backup job func (h *Handler) CreateJob(c *gin.Context) { var req CreateJobRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Validate job type validJobTypes := map[string]bool{ "Backup": true, "Restore": true, "Verify": true, "Copy": true, "Migrate": true, } if !validJobTypes[req.JobType] { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid job_type"}) return } // Validate job level validJobLevels := map[string]bool{ "Full": true, "Incremental": true, "Differential": true, "Since": true, } if !validJobLevels[req.JobLevel] { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid job_level"}) return } job, err := h.service.CreateJob(c.Request.Context(), req) if err != nil { h.logger.Error("Failed to create job", "error", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create job"}) return } c.JSON(http.StatusCreated, job) } // ExecuteBconsoleCommand executes a bconsole command func (h *Handler) ExecuteBconsoleCommand(c *gin.Context) { var req struct { Command string `json:"command" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "command is required"}) return } output, err := h.service.ExecuteBconsoleCommand(c.Request.Context(), req.Command) if err != nil { h.logger.Error("Failed to execute bconsole command", "error", err, "command", req.Command) c.JSON(http.StatusInternalServerError, gin.H{ "error": "failed to execute command", "output": output, "details": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "output": output, }) } // ListClients lists all backup clients with optional filters func (h *Handler) ListClients(c *gin.Context) { opts := ListClientsOptions{} // Parse enabled filter if enabledStr := c.Query("enabled"); enabledStr != "" { enabled := enabledStr == "true" opts.Enabled = &enabled } // Parse search query opts.Search = c.Query("search") clients, err := h.service.ListClients(c.Request.Context(), opts) if err != nil { h.logger.Error("Failed to list clients", "error", err) c.JSON(http.StatusInternalServerError, gin.H{ "error": "failed to list clients", "details": err.Error(), }) return } if clients == nil { clients = []Client{} } c.JSON(http.StatusOK, gin.H{ "clients": clients, "total": len(clients), }) }