You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.8 KiB
Go

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
}