feat: Add compliance handler with DSR management, consent tracking, audit logging, and data residency endpoints

- Add ComplianceHandler struct with service and logger dependencies and NewComplianceHandler constructor
- Add CreateDSR, GetDSR, ListDSRs, and ProcessDSR methods for data subject request management
- Add RecordConsent, RevokeConsent, and GetConsents methods for consent tracking with IP and user agent capture
- Add QueryAuditLogs method with jurisdiction, actor, and action filtering
- Add SetDataRes
This commit is contained in:
nutcas3
2026-05-03 10:50:50 +03:00
parent b2f92cc8f4
commit 7be483dbd5
@@ -0,0 +1,171 @@
package handlers
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/compliance"
"github.com/sirupsen/logrus"
)
// ComplianceHandler handles compliance API requests
type ComplianceHandler struct {
service *compliance.Service
logger *logrus.Logger
}
// NewComplianceHandler creates a new compliance handler
func NewComplianceHandler(service *compliance.Service, logger *logrus.Logger) *ComplianceHandler {
return &ComplianceHandler{service: service, logger: logger}
}
// CreateDSR creates a data subject request
func (h *ComplianceHandler) CreateDSR(c *gin.Context) {
var req compliance.DataSubjectRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
req.TenantID = c.GetHeader("X-Tenant-ID")
if err := h.service.CreateDSR(c.Request.Context(), &req); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, req)
}
// GetDSR retrieves a data subject request
func (h *ComplianceHandler) GetDSR(c *gin.Context) {
id := c.Param("id")
dsr, err := h.service.GetDSR(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, dsr)
}
// ListDSRs lists data subject requests
func (h *ComplianceHandler) ListDSRs(c *gin.Context) {
tenantID := c.GetHeader("X-Tenant-ID")
var status *compliance.DSRStatus
if s := c.Query("status"); s != "" {
st := compliance.DSRStatus(s)
status = &st
}
dsrs, err := h.service.ListDSRs(c.Request.Context(), tenantID, status)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, dsrs)
}
// ProcessDSR processes a data subject request
func (h *ComplianceHandler) ProcessDSR(c *gin.Context) {
id := c.Param("id")
if err := h.service.ProcessDSR(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "processing"})
}
// RecordConsent records user consent
func (h *ComplianceHandler) RecordConsent(c *gin.Context) {
var consent compliance.ConsentRecord
if err := c.ShouldBindJSON(&consent); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
consent.TenantID = c.GetHeader("X-Tenant-ID")
consent.IPAddress = c.ClientIP()
consent.UserAgent = c.GetHeader("User-Agent")
if err := h.service.RecordConsent(c.Request.Context(), &consent); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, consent)
}
// RevokeConsent revokes user consent
func (h *ComplianceHandler) RevokeConsent(c *gin.Context) {
subjectID := c.Param("subject_id")
consentType := compliance.ConsentType(c.Query("type"))
if err := h.service.RevokeConsent(c.Request.Context(), subjectID, consentType); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "revoked"})
}
// GetConsents retrieves consent records for a subject
func (h *ComplianceHandler) GetConsents(c *gin.Context) {
subjectID := c.Param("subject_id")
consents, err := h.service.GetConsents(c.Request.Context(), subjectID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, consents)
}
// QueryAuditLogs queries audit logs
func (h *ComplianceHandler) QueryAuditLogs(c *gin.Context) {
tenantID := c.GetHeader("X-Tenant-ID")
filter := &compliance.AuditLogFilter{
Jurisdiction: c.Query("jurisdiction"),
ActorID: c.Query("actor_id"),
Action: c.Query("action"),
Limit: 100,
}
logs, err := h.service.QueryAuditLogs(c.Request.Context(), tenantID, filter)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, logs)
}
// SetDataResidency sets data residency configuration
func (h *ComplianceHandler) SetDataResidency(c *gin.Context) {
var config compliance.DataResidencyConfig
if err := c.ShouldBindJSON(&config); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
config.TenantID = c.GetHeader("X-Tenant-ID")
if err := h.service.SetDataResidency(c.Request.Context(), &config); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, config)
}
// GetDataResidency retrieves data residency configuration
func (h *ComplianceHandler) GetDataResidency(c *gin.Context) {
tenantID := c.GetHeader("X-Tenant-ID")
config, err := h.service.GetDataResidency(c.Request.Context(), tenantID)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, config)
}