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>
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
|
||||
)
|
||||
|
||||
// GetByRegulation returns obligations grouped by regulation
|
||||
// GET /sdk/v1/ucca/obligations/:assessmentId/by-regulation
|
||||
func (h *ObligationsHandlers) GetByRegulation(c *gin.Context) {
|
||||
tenantID := rbac.GetTenantID(c)
|
||||
assessmentID := c.Param("assessmentId")
|
||||
|
||||
if h.store == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Persistence not configured"})
|
||||
return
|
||||
}
|
||||
|
||||
id, err := uuid.Parse(assessmentID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid assessment ID"})
|
||||
return
|
||||
}
|
||||
|
||||
assessment, err := h.store.GetAssessment(c.Request.Context(), tenantID, id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Assessment not found"})
|
||||
return
|
||||
}
|
||||
|
||||
grouped := h.registry.GroupByRegulation(assessment.Overview.Obligations)
|
||||
|
||||
c.JSON(http.StatusOK, ucca.ObligationsByRegulationResponse{
|
||||
Regulations: grouped,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByDeadline returns obligations grouped by deadline timeframe
|
||||
// GET /sdk/v1/ucca/obligations/:assessmentId/by-deadline
|
||||
func (h *ObligationsHandlers) GetByDeadline(c *gin.Context) {
|
||||
tenantID := rbac.GetTenantID(c)
|
||||
assessmentID := c.Param("assessmentId")
|
||||
|
||||
if h.store == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Persistence not configured"})
|
||||
return
|
||||
}
|
||||
|
||||
id, err := uuid.Parse(assessmentID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid assessment ID"})
|
||||
return
|
||||
}
|
||||
|
||||
assessment, err := h.store.GetAssessment(c.Request.Context(), tenantID, id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Assessment not found"})
|
||||
return
|
||||
}
|
||||
|
||||
grouped := h.registry.GroupByDeadline(assessment.Overview.Obligations)
|
||||
|
||||
c.JSON(http.StatusOK, grouped)
|
||||
}
|
||||
|
||||
// GetByResponsible returns obligations grouped by responsible role
|
||||
// GET /sdk/v1/ucca/obligations/:assessmentId/by-responsible
|
||||
func (h *ObligationsHandlers) GetByResponsible(c *gin.Context) {
|
||||
tenantID := rbac.GetTenantID(c)
|
||||
assessmentID := c.Param("assessmentId")
|
||||
|
||||
if h.store == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Persistence not configured"})
|
||||
return
|
||||
}
|
||||
|
||||
id, err := uuid.Parse(assessmentID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid assessment ID"})
|
||||
return
|
||||
}
|
||||
|
||||
assessment, err := h.store.GetAssessment(c.Request.Context(), tenantID, id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Assessment not found"})
|
||||
return
|
||||
}
|
||||
|
||||
grouped := h.registry.GroupByResponsible(assessment.Overview.Obligations)
|
||||
|
||||
c.JSON(http.StatusOK, ucca.ObligationsByResponsibleResponse{
|
||||
ByRole: grouped,
|
||||
})
|
||||
}
|
||||
|
||||
// ListRegulations returns all available regulation modules
|
||||
// GET /sdk/v1/ucca/obligations/regulations
|
||||
func (h *ObligationsHandlers) ListRegulations(c *gin.Context) {
|
||||
modules := h.registry.ListModules()
|
||||
|
||||
c.JSON(http.StatusOK, ucca.AvailableRegulationsResponse{
|
||||
Regulations: modules,
|
||||
})
|
||||
}
|
||||
|
||||
// GetDecisionTree returns the decision tree for a specific regulation
|
||||
// GET /sdk/v1/ucca/obligations/regulations/:regulationId/decision-tree
|
||||
func (h *ObligationsHandlers) GetDecisionTree(c *gin.Context) {
|
||||
regulationID := c.Param("regulationId")
|
||||
|
||||
tree, err := h.registry.GetDecisionTree(regulationID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, tree)
|
||||
}
|
||||
|
||||
// GetTOMControlsForObligation returns TOM controls linked to an obligation
|
||||
// GET /sdk/v1/ucca/obligations/:id/tom-controls
|
||||
func (h *ObligationsHandlers) GetTOMControlsForObligation(c *gin.Context) {
|
||||
obligationID := c.Param("obligationId")
|
||||
|
||||
if h.tomMapper == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "TOM mapping not available"})
|
||||
return
|
||||
}
|
||||
|
||||
controls := h.tomMapper.GetControlsForObligation(obligationID)
|
||||
controlIDs := h.tomMapper.GetControlIDsForObligation(obligationID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"obligation_id": obligationID,
|
||||
"control_ids": controlIDs,
|
||||
"controls": controls,
|
||||
"count": len(controls),
|
||||
})
|
||||
}
|
||||
|
||||
// GapAnalysis performs a TOM control gap analysis
|
||||
// POST /sdk/v1/ucca/obligations/gap-analysis
|
||||
func (h *ObligationsHandlers) GapAnalysis(c *gin.Context) {
|
||||
if h.gapAnalyzer == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Gap analysis not available"})
|
||||
return
|
||||
}
|
||||
|
||||
var req ucca.GapAnalysisRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
result := h.gapAnalyzer.Analyze(&req)
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// GetObligationsForControl returns obligations linked to a TOM control
|
||||
// GET /sdk/v1/ucca/obligations/tom-controls/:controlId/obligations
|
||||
func (h *ObligationsHandlers) GetObligationsForControl(c *gin.Context) {
|
||||
controlID := c.Param("controlId")
|
||||
|
||||
if h.tomMapper == nil {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "TOM mapping not available"})
|
||||
return
|
||||
}
|
||||
|
||||
obligationIDs := h.tomMapper.GetObligationsForControl(controlID)
|
||||
|
||||
var control *ucca.TOMControl
|
||||
if h.tomIndex != nil {
|
||||
control, _ = h.tomIndex.GetControl(controlID)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"control_id": controlID,
|
||||
"control": control,
|
||||
"obligation_ids": obligationIDs,
|
||||
"count": len(obligationIDs),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user