#!/usr/bin/env python3 """Profil de client (firma), asociat cu mai multe numere de WhatsApp. Un singur fisier `clients.json`: la ordinul de marime de aici (zeci de firme) nu justifica o baza de date, si un singur fisier e mai usor de editat de mana din dashboard decat mai multe fisiere sincronizate intre ele. Numerele stau IN clientul lor (nu intr-o mapare separata numar->client), fiindca cautarea e mereu "cine e clientul care are numarul X" — o mapare separata ar trebui tinuta sincronizata cu clients.json, doua surse de adevar pentru acelasi lucru. Mesaj de grup fara `participant` (adica bridge-ul n-a stiut cine a scris) nu identifica niciun client: JID-ul de grup nu e un numar de telefon, si a-l cauta printre numere ar asocia gresit tot grupul cu primul client care se potriveste din intamplare. """ from __future__ import annotations import json import os import re import config def _norm(numar_brut: str) -> str: return re.sub(r"\D", "", numar_brut or "") def numar(msg: dict) -> str: """Numarul care a scris, normalizat (doar cifre). Gol daca nu se poate sti.""" jid = msg.get("participant") if not jid: frm = msg.get("from") or "" if frm.endswith("@g.us"): return "" # grup fara participant: nu stim cine a scris jid = frm return _norm(jid.split("@")[0]) def _load() -> dict: try: return json.loads(config.CLIENTS_FILE.read_text(encoding="utf-8")) except (OSError, ValueError): return {} def profil(msg_sau_jid) -> str | None: """Textul de profil al clientului asociat, sau `None` daca numarul nu e cunoscut.""" n = numar(msg_sau_jid) if isinstance(msg_sau_jid, dict) else _norm( str(msg_sau_jid).split("@")[0]) if not n: return None for client in _load().values(): if n in client.get("numere", []): return client.get("profil") return None def toti() -> dict: return _load() def salveaza(id: str, nume: str, profil: str, numere: list[str]) -> None: """Upsert. Normalizeaza fiecare numar acum, ca lookup-ul sa functioneze mereu.""" date = _load() date[id] = { "nume": nume, "profil": profil, "numere": [n for n in (_norm(x) for x in numere) if n], } tmp = config.CLIENTS_FILE.with_suffix(".tmp") config.STATE_DIR.mkdir(parents=True, exist_ok=True) tmp.write_text(json.dumps(date, ensure_ascii=False, indent=2), encoding="utf-8") os.replace(tmp, config.CLIENTS_FILE) def sterge(id: str) -> bool: date = _load() if id not in date: return False del date[id] tmp = config.CLIENTS_FILE.with_suffix(".tmp") config.STATE_DIR.mkdir(parents=True, exist_ok=True) tmp.write_text(json.dumps(date, ensure_ascii=False, indent=2), encoding="utf-8") os.replace(tmp, config.CLIENTS_FILE) return True