Files
breakpilot-compliance/ai-compliance-sdk/internal/api/handlers/rbac_handlers.go
Sharang Parnerkar 13f57c4519 refactor(go): split obligations, portfolio, rbac, whistleblower handlers and stores, roadmap parser
Split 7 files exceeding the 500 LOC hard cap into 16 files, all under 500 LOC.
No exported symbols renamed; zero behavior changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 10:00:15 +02:00

166 lines
4.3 KiB
Go

package handlers
import (
"net/http"
"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// RBACHandlers handles RBAC-related API endpoints
type RBACHandlers struct {
store *rbac.Store
service *rbac.Service
policyEngine *rbac.PolicyEngine
}
// NewRBACHandlers creates new RBAC handlers
func NewRBACHandlers(store *rbac.Store, service *rbac.Service, policyEngine *rbac.PolicyEngine) *RBACHandlers {
return &RBACHandlers{
store: store,
service: service,
policyEngine: policyEngine,
}
}
// ============================================================================
// Tenant Endpoints
// ============================================================================
// ListTenants returns all tenants
func (h *RBACHandlers) ListTenants(c *gin.Context) {
tenants, err := h.store.ListTenants(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"tenants": tenants})
}
// GetTenant returns a tenant by ID
func (h *RBACHandlers) GetTenant(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid tenant ID"})
return
}
tenant, err := h.store.GetTenant(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "tenant not found"})
return
}
c.JSON(http.StatusOK, tenant)
}
// CreateTenant creates a new tenant
func (h *RBACHandlers) CreateTenant(c *gin.Context) {
var tenant rbac.Tenant
if err := c.ShouldBindJSON(&tenant); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := h.store.CreateTenant(c.Request.Context(), &tenant); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, tenant)
}
// UpdateTenant updates a tenant
func (h *RBACHandlers) UpdateTenant(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid tenant ID"})
return
}
var tenant rbac.Tenant
if err := c.ShouldBindJSON(&tenant); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
tenant.ID = id
if err := h.store.UpdateTenant(c.Request.Context(), &tenant); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, tenant)
}
// ============================================================================
// Namespace Endpoints
// ============================================================================
// ListNamespaces returns namespaces for a tenant
func (h *RBACHandlers) ListNamespaces(c *gin.Context) {
tenantID, err := uuid.Parse(c.Param("id"))
if err != nil {
tenantID = rbac.GetTenantID(c)
}
if tenantID == uuid.Nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
return
}
namespaces, err := h.store.ListNamespaces(c.Request.Context(), tenantID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"namespaces": namespaces})
}
// GetNamespace returns a namespace by ID
func (h *RBACHandlers) GetNamespace(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid namespace ID"})
return
}
namespace, err := h.store.GetNamespace(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "namespace not found"})
return
}
c.JSON(http.StatusOK, namespace)
}
// CreateNamespace creates a new namespace
func (h *RBACHandlers) CreateNamespace(c *gin.Context) {
tenantID, err := uuid.Parse(c.Param("id"))
if err != nil {
tenantID = rbac.GetTenantID(c)
}
if tenantID == uuid.Nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
return
}
var namespace rbac.Namespace
if err := c.ShouldBindJSON(&namespace); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
namespace.TenantID = tenantID
if err := h.store.CreateNamespace(c.Request.Context(), &namespace); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, namespace)
}