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>
166 lines
4.3 KiB
Go
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)
|
|
}
|