rmm2/backend/api/tasks.go

163 lines
4.2 KiB
Go

package api
import (
"encoding/json"
"log"
"net/http"
"strconv"
"time"
"github.com/cynfo/rmm-backend/ws"
)
// GET /api/v1/tasks
func (h *Handler) listTasks(w http.ResponseWriter, r *http.Request) {
limit := 50
offset := 0
agentID := r.URL.Query().Get("agent_id")
status := r.URL.Query().Get("status")
action := r.URL.Query().Get("action")
if l := r.URL.Query().Get("limit"); l != "" {
if n, err := strconv.Atoi(l); err == nil && n > 0 {
limit = n
}
}
if o := r.URL.Query().Get("offset"); o != "" {
if n, err := strconv.Atoi(o); err == nil && n >= 0 {
offset = n
}
}
tasks, total, err := h.db.GetTasks(limit, offset, agentID, status, action)
if err != nil {
log.Printf("Tasks laden fehlgeschlagen: %v", err)
writeError(w, http.StatusInternalServerError, "Fehler beim Laden")
return
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"data": tasks,
"total": total,
})
}
// GET /api/v1/tasks/{id}
func (h *Handler) getTask(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
writeError(w, http.StatusBadRequest, "Ungueltige Task-ID")
return
}
task, err := h.db.GetTask(id)
if err != nil {
writeError(w, http.StatusInternalServerError, "Fehler beim Laden")
return
}
if task == nil {
writeError(w, http.StatusNotFound, "Task nicht gefunden")
return
}
writeJSON(w, http.StatusOK, task)
}
// POST /api/v1/tasks
func (h *Handler) createTask(hub *ws.Hub) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
AgentID string `json:"agent_id"`
Action string `json:"action"`
ScheduledAt string `json:"scheduled_at"`
WebhookURL string `json:"webhook_url"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "Ungueltige Anfrage")
return
}
if req.AgentID == "" || req.Action == "" {
writeError(w, http.StatusBadRequest, "agent_id und action sind erforderlich")
return
}
// Validate action
if req.Action != "backup" && req.Action != "update" {
writeError(w, http.StatusBadRequest, "Ungueltige Aktion (backup, update)")
return
}
// Check agent exists
agent, _, err := h.db.GetAgent(req.AgentID)
if err != nil || agent == nil {
writeError(w, http.StatusNotFound, "Agent nicht gefunden")
return
}
// Get user from context
createdBy := "api-key"
if claims, ok := r.Context().Value(UserContextKey).(*JWTClaims); ok {
createdBy = claims.Username
}
task, err := h.db.CreateTask(req.AgentID, req.Action, req.ScheduledAt, req.WebhookURL, createdBy)
if err != nil {
log.Printf("Task erstellen fehlgeschlagen: %v", err)
writeError(w, http.StatusInternalServerError, "Task erstellen fehlgeschlagen: "+err.Error())
return
}
h.auditLog(r, "task.create", "task", strconv.Itoa(task.ID), agent.Name, req.Action)
// If scheduled_at is in the past or now, trigger immediate execution
if req.ScheduledAt == "" {
// Already scheduled for now, scheduler will pick it up within 30s
} else {
schedTime, err := time.Parse(time.RFC3339, req.ScheduledAt)
if err == nil && !schedTime.After(time.Now()) {
// In the past — scheduler picks it up
}
}
writeJSON(w, http.StatusCreated, task)
}
}
// POST /api/v1/tasks/{id}/cancel
func (h *Handler) cancelTask(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
writeError(w, http.StatusBadRequest, "Ungueltige Task-ID")
return
}
if err := h.db.CancelTask(id); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
h.auditLog(r, "task.cancel", "task", idStr, "", "")
writeJSON(w, http.StatusOK, map[string]string{"message": "Task abgebrochen"})
}
// DELETE /api/v1/tasks/{id}
func (h *Handler) deleteTask(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
writeError(w, http.StatusBadRequest, "Ungueltige Task-ID")
return
}
if err := h.db.DeleteTask(id); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
h.auditLog(r, "task.delete", "task", idStr, "", "")
writeJSON(w, http.StatusOK, map[string]string{"message": "Task geloescht"})
}