package handler import ( "baron-sso-backend/internal/domain" "baron-sso-backend/internal/repository" "baron-sso-backend/internal/service" "log/slog" "runtime" "strconv" "time" "github.com/gofiber/fiber/v2" ) type AdminHandler struct { Keto service.KetoService KetoOutbox repository.KetoOutboxRepository DeveloperSvc *service.DeveloperService } func NewAdminHandler(keto service.KetoService, ketoOutbox repository.KetoOutboxRepository, developerSvc *service.DeveloperService) *AdminHandler { return &AdminHandler{ Keto: keto, KetoOutbox: ketoOutbox, DeveloperSvc: developerSvc, } } func (h *AdminHandler) CheckAuth(c *fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "ok"}) } // GetSystemStats returns runtime statistics for monitoring func (h *AdminHandler) GetSystemStats(c *fiber.Ctx) error { var m runtime.MemStats runtime.ReadMemStats(&m) stats := fiber.Map{ "goroutines": runtime.NumGoroutine(), "cpus": runtime.NumCPU(), "memory": fiber.Map{ "alloc": m.Alloc, "totalAlign": m.TotalAlloc, "sys": m.Sys, "numGC": m.NumGC, }, "timestamp": time.Now(), } return c.Status(fiber.StatusOK).JSON(stats) } func (h *AdminHandler) ListDeveloperRequests(c *fiber.Ctx) error { status := c.Query("status") requests, err := h.DeveloperSvc.ListRequests(c.Context(), status) if err != nil { return errorJSON(c, fiber.StatusInternalServerError, err.Error()) } return c.JSON(requests) } func (h *AdminHandler) ApproveDeveloperRequest(c *fiber.Ctx) error { idStr := c.Params("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { return errorJSON(c, fiber.StatusBadRequest, "invalid request id") } var reqBody struct { AdminNotes string `json:"adminNotes"` } if err := c.BodyParser(&reqBody); err != nil { return errorJSON(c, fiber.StatusBadRequest, "invalid request body") } // 1. Get request to know userID and tenantID devReq, err := h.DeveloperSvc.GetRequestByID(c.Context(), uint(id)) if err != nil { return errorJSON(c, fiber.StatusInternalServerError, "failed to fetch request details") } // 2. Approve in DB if err := h.DeveloperSvc.ApproveRequest(c.Context(), uint(id), reqBody.AdminNotes); err != nil { return errorJSON(c, fiber.StatusInternalServerError, err.Error()) } // 3. Grant Keto Permissions via Outbox if h.KetoOutbox != nil { subject := "User:" + devReq.UserID permissions := []string{"view_dev_console", "grant_dev_permissions"} for _, relation := range permissions { err := h.KetoOutbox.Create(c.Context(), &domain.KetoOutbox{ Namespace: "Tenant", Object: devReq.TenantID, Relation: relation, Subject: subject, Action: domain.KetoOutboxActionCreate, }) if err != nil { slog.Warn("failed to create keto outbox for developer approval", "relation", relation, "userID", devReq.UserID, "error", err) } } } return c.JSON(fiber.Map{"status": "ok"}) } func (h *AdminHandler) RejectDeveloperRequest(c *fiber.Ctx) error { idStr := c.Params("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { return errorJSON(c, fiber.StatusBadRequest, "invalid request id") } var reqBody struct { AdminNotes string `json:"adminNotes"` } if err := c.BodyParser(&reqBody); err != nil { return errorJSON(c, fiber.StatusBadRequest, "invalid request body") } if err := h.DeveloperSvc.RejectRequest(c.Context(), uint(id), reqBody.AdminNotes); err != nil { return errorJSON(c, fiber.StatusInternalServerError, err.Error()) } return c.JSON(fiber.Map{"status": "ok"}) }