feat: IAB TCF 2.2 — TC String encoder + purpose mapping + UI
- TCFEncoderService: generates base64url-encoded TC Strings per IAB spec with 12 purposes, vendor consent bitfield, CMP metadata - Category-to-purpose mapping (necessary→none, statistics→1,7,8,9,10, marketing→1,2,3,4,5,6,7,12, functional→1,11) - tcf_routes: 5 endpoints (purposes, features, mapping, encode, encode-categories) - banner_consent_service: auto-generates TC String when tcf_enabled=true - TCFSettings.tsx: enable/disable toggle, purpose grid with category mapping, TC String test generator, CMP registration info - New "TCF/IAB" tab in cookie-banner page (7 tabs total) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -133,6 +133,24 @@ class BannerConsentService:
|
||||
return max(v.retention_days for v in vendors if v.retention_days)
|
||||
return max((CATEGORY_RETENTION_DAYS.get(c, 365) for c in categories), default=365)
|
||||
|
||||
def _maybe_generate_tc_string(
|
||||
self, tenant_id: uuid.UUID, site_id: str, categories: list[str],
|
||||
) -> Optional[str]:
|
||||
"""Generate TC String if TCF is enabled for this site."""
|
||||
config = (
|
||||
self.db.query(BannerSiteConfigDB)
|
||||
.filter(BannerSiteConfigDB.tenant_id == tenant_id, BannerSiteConfigDB.site_id == site_id)
|
||||
.first()
|
||||
)
|
||||
if not config or not config.tcf_enabled:
|
||||
return None
|
||||
try:
|
||||
from compliance.services.tcf_encoder_service import TCFEncoderService
|
||||
encoder = TCFEncoderService()
|
||||
return encoder.encode_from_categories(categories)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Consent CRUD (public SDK)
|
||||
# ------------------------------------------------------------------
|
||||
@@ -163,6 +181,10 @@ class BannerConsentService:
|
||||
expires_at = now + timedelta(days=retention)
|
||||
config_hash, config_ver = self._compute_config_hash(tid, site_id)
|
||||
|
||||
# Auto-generate TC String if TCF is enabled for this site
|
||||
if not consent_string:
|
||||
consent_string = self._maybe_generate_tc_string(tid, site_id, categories)
|
||||
|
||||
existing = (
|
||||
self.db.query(BannerConsentDB)
|
||||
.filter(
|
||||
|
||||
Reference in New Issue
Block a user