package http import ( "strconv" "github.com/gofiber/fiber/v3" appadmin "knowfoolery/backend/services/admin-service/internal/application/admin" "knowfoolery/backend/shared/infra/auth/rbac" "knowfoolery/backend/shared/infra/auth/zitadel" "knowfoolery/backend/shared/infra/observability/logging" "knowfoolery/backend/shared/infra/observability/metrics" "knowfoolery/backend/shared/infra/utils/httputil" ) // Handler wires HTTP endpoints. type Handler struct { svc *appadmin.Service logger *logging.Logger metrics *metrics.Metrics } // NewHandler creates HTTP handlers for admin endpoints. func NewHandler(svc *appadmin.Service, logger *logging.Logger, metrics *metrics.Metrics) *Handler { return &Handler{svc: svc, logger: logger, metrics: metrics} } func (h *Handler) AdminAuth(c fiber.Ctx) error { actorID := zitadel.GetUserID(c) actorEmail := zitadel.GetUserEmail(c) roles := zitadel.GetUserRoles(c) mfa := zitadel.IsMFAVerified(c) _ = h.svc.AppendAudit(c.Context(), actorID, actorEmail, "admin.auth", "admin", map[string]any{ "mfa": mfa, "roles": roles, }) return c.JSON(fiber.Map{ "ok": true, "actor_id": actorID, "actor_email": actorEmail, "roles": roles, "mfa": mfa, }) } func (h *Handler) Dashboard(c fiber.Ctx) error { roles := zitadel.GetUserRoles(c) if !rbac.UserHasPermission(roles, rbac.PermissionViewDashboard) { return httputil.Forbidden(c, "dashboard permission required") } actorID := zitadel.GetUserID(c) actorEmail := zitadel.GetUserEmail(c) _ = h.svc.AppendAudit(c.Context(), actorID, actorEmail, "admin.dashboard.view", "dashboard", nil) resp, err := h.svc.Dashboard(c.Context()) if err != nil { h.logger.WithError(err).Error("dashboard failed") return httputil.InternalError(c, "dashboard failed") } return c.JSON(resp) } func (h *Handler) AuditList(c fiber.Ctx) error { roles := zitadel.GetUserRoles(c) if !rbac.UserHasPermission(roles, rbac.PermissionViewAuditLog) { return httputil.Forbidden(c, "audit permission required") } limit := parseIntQuery(c, "limit", 50) offset := parseIntQuery(c, "offset", 0) actorID := zitadel.GetUserID(c) actorEmail := zitadel.GetUserEmail(c) _ = h.svc.AppendAudit(c.Context(), actorID, actorEmail, "admin.audit.view", "audit", map[string]any{ "limit": limit, "offset": offset, }) entries, err := h.svc.ListAudit(c.Context(), limit, offset) if err != nil { h.logger.WithError(err).Error("audit list failed") return httputil.InternalError(c, "audit list failed") } return c.JSON(fiber.Map{ "items": entries, "limit": limit, "offset": offset, }) } func parseIntQuery(c fiber.Ctx, key string, fallback int) int { v := c.Query(key) if v == "" { return fallback } n, err := strconv.Atoi(v) if err != nil { return fallback } return n }