Files
breakpilot-core/consent-service/internal/handlers/cookies_public.go
Benjamin Admin 92c86ec6ba [split-required] [guardrail-change] Enforce 500 LOC budget across all services
Install LOC guardrails (check-loc.sh, architecture.md, pre-commit hook)
and split all 44 files exceeding 500 LOC into domain-focused modules:

- consent-service (Go): models, handlers, services, database splits
- backend-core (Python): security_api, rbac_api, pdf_service, auth splits
- admin-core (TypeScript): 5 page.tsx + sidebar extractions
- pitch-deck (TypeScript): 6 slides, 3 UI components, engine.ts splits
- voice-service (Python): enhanced_task_orchestrator split

Result: 0 violations, 36 exempted (pipeline, tests, pure-data files).
Go build verified clean. No behavior changes — pure structural splits.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 00:09:30 +02:00

159 lines
4.2 KiB
Go

package handlers
import (
"context"
"net/http"
"time"
"github.com/breakpilot/consent-service/internal/middleware"
"github.com/breakpilot/consent-service/internal/models"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// ========================================
// PUBLIC ENDPOINTS - Cookie Consent
// ========================================
// GetCookieCategories returns all active cookie categories
func (h *Handler) GetCookieCategories(c *gin.Context) {
language := c.DefaultQuery("language", "de")
ctx := context.Background()
rows, err := h.db.Pool.Query(ctx, `
SELECT id, name, display_name_de, display_name_en, description_de, description_en,
is_mandatory, sort_order
FROM cookie_categories
WHERE is_active = true
ORDER BY sort_order ASC
`)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch categories"})
return
}
defer rows.Close()
var categories []map[string]interface{}
for rows.Next() {
var cat models.CookieCategory
if err := rows.Scan(&cat.ID, &cat.Name, &cat.DisplayNameDE, &cat.DisplayNameEN,
&cat.DescriptionDE, &cat.DescriptionEN, &cat.IsMandatory, &cat.SortOrder); err != nil {
continue
}
// Return localized data
displayName := cat.DisplayNameDE
description := cat.DescriptionDE
if language == "en" && cat.DisplayNameEN != nil {
displayName = *cat.DisplayNameEN
if cat.DescriptionEN != nil {
description = cat.DescriptionEN
}
}
categories = append(categories, map[string]interface{}{
"id": cat.ID,
"name": cat.Name,
"display_name": displayName,
"description": description,
"is_mandatory": cat.IsMandatory,
})
}
c.JSON(http.StatusOK, gin.H{"categories": categories})
}
// SetCookieConsent sets cookie preferences for a user
func (h *Handler) SetCookieConsent(c *gin.Context) {
var req models.CookieConsentRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
return
}
userID, err := middleware.GetUserID(c)
if err != nil || userID == uuid.Nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
return
}
ctx := context.Background()
ipAddress := middleware.GetClientIP(c)
userAgent := middleware.GetUserAgent(c)
// Process each category
for _, cat := range req.Categories {
categoryID, err := uuid.Parse(cat.CategoryID)
if err != nil {
continue
}
_, err = h.db.Pool.Exec(ctx, `
INSERT INTO cookie_consents (user_id, category_id, consented)
VALUES ($1, $2, $3)
ON CONFLICT (user_id, category_id)
DO UPDATE SET consented = $3, updated_at = NOW()
`, userID, categoryID, cat.Consented)
if err != nil {
continue
}
}
// Log to audit trail
h.logAudit(ctx, &userID, "cookie_consent_updated", "cookie", nil, nil, ipAddress, userAgent)
c.JSON(http.StatusOK, gin.H{"message": "Cookie preferences saved"})
}
// GetMyCookieConsent returns cookie preferences for the current user
func (h *Handler) GetMyCookieConsent(c *gin.Context) {
userID, err := middleware.GetUserID(c)
if err != nil || userID == uuid.Nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
return
}
ctx := context.Background()
rows, err := h.db.Pool.Query(ctx, `
SELECT cc.category_id, cc.consented, cc.updated_at,
cat.name, cat.display_name_de, cat.is_mandatory
FROM cookie_consents cc
JOIN cookie_categories cat ON cc.category_id = cat.id
WHERE cc.user_id = $1
`, userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch preferences"})
return
}
defer rows.Close()
var consents []map[string]interface{}
for rows.Next() {
var (
categoryID uuid.UUID
consented bool
updatedAt time.Time
name string
displayName string
isMandatory bool
)
if err := rows.Scan(&categoryID, &consented, &updatedAt, &name, &displayName, &isMandatory); err != nil {
continue
}
consents = append(consents, map[string]interface{}{
"category_id": categoryID,
"name": name,
"display_name": displayName,
"consented": consented,
"is_mandatory": isMandatory,
"updated_at": updatedAt,
})
}
c.JSON(http.StatusOK, gin.H{"cookie_consents": consents})
}