""" FastAPI routes for IAB TCF 2.2 (Transparency & Consent Framework). Endpoints: GET /tcf/purposes — list 12 IAB purposes with translations GET /tcf/special-features — list 2 IAB special features GET /tcf/category-mapping — banner category → IAB purpose mapping POST /tcf/encode — generate TC String from consent decisions POST /tcf/encode-categories — generate TC String from banner categories """ import logging from typing import Optional, List, Dict from fastapi import APIRouter, Depends from pydantic import BaseModel from sqlalchemy.orm import Session from classroom_engine.database import get_db from .tenant_utils import get_tenant_id as _get_tenant_id from compliance.services.tcf_encoder_service import TCFEncoderService logger = logging.getLogger(__name__) router = APIRouter(prefix="/tcf", tags=["tcf"]) class TCFEncodeRequest(BaseModel): purpose_consents: Dict[int, bool] = {} vendor_consents: Dict[int, bool] = {} purpose_li: Optional[Dict[int, bool]] = None special_features: Optional[Dict[int, bool]] = None cmp_id: int = 1 cmp_version: int = 1 consent_language: str = "DE" class TCFCategoryEncodeRequest(BaseModel): categories: List[str] = [] vendor_consents: Optional[Dict[int, bool]] = None cmp_id: int = 1 consent_language: str = "DE" @router.get("/purposes") def list_purposes(): return TCFEncoderService.get_purposes() @router.get("/special-features") def list_special_features(): return TCFEncoderService.get_special_features() @router.get("/category-mapping") def get_category_mapping(): return TCFEncoderService.get_category_purpose_map() @router.post("/encode") def encode_tc_string(body: TCFEncodeRequest): encoder = TCFEncoderService( cmp_id=body.cmp_id, cmp_version=body.cmp_version, consent_language=body.consent_language, ) tc_string = encoder.encode( purpose_consents=body.purpose_consents, vendor_consents=body.vendor_consents, purpose_li=body.purpose_li, special_features=body.special_features, ) return {"tc_string": tc_string, "version": 2} @router.post("/encode-categories") def encode_from_categories(body: TCFCategoryEncodeRequest): encoder = TCFEncoderService( cmp_id=body.cmp_id, consent_language=body.consent_language, ) tc_string = encoder.encode_from_categories( categories=body.categories, vendor_consents=body.vendor_consents, ) # Also return which purposes were set from compliance.services.tcf_encoder_service import CATEGORY_PURPOSE_MAP purpose_ids = set() for cat in body.categories: purpose_ids.update(CATEGORY_PURPOSE_MAP.get(cat, [])) return { "tc_string": tc_string, "version": 2, "purposes_consented": sorted(purpose_ids), "categories": body.categories, }