feat(consent-tester): Phase B — named CMP library + plugin architecture
cmp_extractor.py refactored to thin coordinator (123 LOC, was 223). Discovers all CMP modules via cmp_library/_registry.py:load_all() at import time. Restart consent-tester to pick up new modules. New cmp_library/ folder: - _registry.py: auto-discovers all modules with MATCHER + reconstruct() - epaas.py: BMW Group ePaaS (extracted from cmp_extractor) - onetrust.py: cdn.cookielaw.org Groups/Cookies schema - cookiebot.py: consent.cookiebot.com Categories schema - usercentrics.py: api.usercentrics.eu services schema - didomi.py: sdk.privacy-center.org notice + vendors + purposes - trustarc.py: consent.trustarc.com categories + vendors Each module: - MATCHER: re.Pattern matching the CMP JSON endpoint URL - reconstruct(d: dict) -> str: builds German Markdown cookie-policy text Phase E (self-improving) will write auto_*.py files into the same folder; _registry already picks those up via pkgutil.iter_modules.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
"""Usercentrics CMP.
|
||||
|
||||
URLs:
|
||||
- api.usercentrics.eu/settings/<id>/<lang>.json
|
||||
- app.usercentrics.eu/api/...
|
||||
Schema: services[] with dataProcessor, dataPurpose, cookieMaxAgeSeconds
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
MATCHER = re.compile(r"(?:api|app)\.usercentrics\.eu/.+\.json(?:\?|$)", re.I)
|
||||
|
||||
|
||||
def reconstruct(d: dict) -> str:
|
||||
parts: list[str] = ["# Cookie-Richtlinie (Usercentrics)"]
|
||||
|
||||
services = d.get("services") or d.get("dataProcessingServices") or []
|
||||
if not services and isinstance(d.get("settings"), dict):
|
||||
services = d["settings"].get("services") or []
|
||||
|
||||
for s in services:
|
||||
name = s.get("name") or s.get("dataProcessor") or ""
|
||||
purpose = s.get("dataPurpose") or s.get("purpose") or ""
|
||||
desc = s.get("description") or ""
|
||||
country = s.get("processingCompanyCountry") or s.get("country") or ""
|
||||
max_age = s.get("cookieMaxAgeSeconds")
|
||||
retention = s.get("retentionPeriodDescription") or ""
|
||||
|
||||
parts.append("")
|
||||
parts.append(f"## {name}")
|
||||
if desc:
|
||||
parts.append(desc)
|
||||
if purpose:
|
||||
parts.append(f"Zweck: {purpose}")
|
||||
if country:
|
||||
parts.append(f"Sitz: {country}")
|
||||
if max_age:
|
||||
days = max_age // 86400 if isinstance(max_age, int) else max_age
|
||||
parts.append(f"Speicherdauer: {days} Tage")
|
||||
if retention:
|
||||
parts.append(f"Aufbewahrung: {retention}")
|
||||
|
||||
categories = d.get("categories") or []
|
||||
for c in categories:
|
||||
name = c.get("name") or ""
|
||||
desc = c.get("description") or ""
|
||||
parts.append("")
|
||||
parts.append(f"## Kategorie: {name}")
|
||||
if desc:
|
||||
parts.append(desc)
|
||||
|
||||
return "\n".join(parts)
|
||||
Reference in New Issue
Block a user