scripts/legal.py
scripts/legal.pyBrowse 56 files
580 tokens
2,338 bytes
Token encoding: o200k_base
Snapshot 24fd22b
← Back to SKILL.md
1"""Render opt-out / legal request text from templates/ with safe substitution.2 3Templates use {field} placeholders. Missing fields are left literal (never crash,4never inject blanks that look like real data). Field values come from the5least-disclosure selection in dossier.select_disclosure.6"""7from __future__ import annotations8 9from pathlib import Path10 11import paths12 13 14class _SafeDict(dict):15 def __missing__(self, key): # leave unknown placeholders untouched16 return "{" + key + "}"17 18 19def template_path(name: str) -> Path:20 return paths.templates_dir() / name21 22 23def render(template_name: str, fields: dict) -> str:24 text = template_path(template_name).read_text(encoding="utf-8")25 return text.format_map(_SafeDict(fields))26 27 28def _join_listings(value) -> str:29 if isinstance(value, (list, tuple)):30 return "\n".join(str(v) for v in value)31 return str(value or "")32 33 34def _join_identifiers(value) -> str:35 """Render the subject's OWN identifiers as a bullet list for an indirect-exposure request."""36 if isinstance(value, (list, tuple)):37 return "\n".join(f" - {v}" for v in value if v)38 return f" - {value}" if value else ""39 40 41def render_optout_email(broker: dict, fields: dict) -> str:42 ctx = dict(fields)43 ctx.setdefault("broker_name", broker.get("name", "the data broker"))44 ctx["listing_urls"] = _join_listings(fields.get("listing_urls"))45 ctx.setdefault("full_name", fields.get("full_name", "[your name]"))46 ctx.setdefault("contact_email", fields.get("contact_email", "[your email]"))47 return render("emails/generic-optout.txt", ctx)48 49 50def render_request(kind: str, broker: dict, fields: dict) -> str:51 """kind: generic | ccpa | ccpa_agent | ccpa_indirect | gdpr"""52 template = {53 "generic": "emails/generic-optout.txt",54 "ccpa": "emails/ccpa-deletion.txt",55 "ccpa_agent": "emails/ccpa-authorized-agent.txt",56 "ccpa_indirect": "emails/ccpa-indirect-deletion.txt",57 "gdpr": "emails/gdpr-erasure.txt",58 }.get(kind, "emails/generic-optout.txt")59 ctx = dict(fields)60 ctx.setdefault("broker_name", broker.get("name", "the data broker"))61 ctx["listing_urls"] = _join_listings(fields.get("listing_urls"))62 ctx["my_identifiers"] = _join_identifiers(fields.get("my_identifiers"))63 return render(template, ctx)64