"""SMTP runtime: публичный payload и запись в .env из админки.""" from __future__ import annotations from typing import Any from config import Settings, get_settings from services.env_file import ( BOOL_ENV_KEYS, SECRET_ENV_KEYS, env_file_path, env_writable, mask_secret, upsert_env_keys, ) from services.mailer import smtp_configured SMTP_ENV_KEYS: tuple[str, ...] = ( "SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASSWORD", "SMTP_FROM", "SMTP_TLS", "SMTP_SSL", ) def smtp_public_dict(settings: Settings) -> dict[str, Any]: path = env_file_path() return { "env_path": str(path), "env_writable": env_writable(path), "configured": smtp_configured(settings), "host": settings.smtp_host, "port": settings.smtp_port, "user": settings.smtp_user, "password_set": bool(settings.smtp_password), "password_hint": mask_secret(settings.smtp_password), "from_email": settings.smtp_from, "tls": bool(settings.smtp_tls), "ssl": bool(settings.smtp_ssl), } def _is_masked_placeholder(value: str) -> bool: v = (value or "").strip() if not v: return True return "…" in v or "•" in v or "..." in v def apply_smtp_body(body: dict[str, Any]) -> Settings: updates: dict[str, str | None] = {} mapping = { "SMTP_HOST": body.get("smtp_host"), "SMTP_PORT": body.get("smtp_port"), "SMTP_USER": body.get("smtp_user"), "SMTP_PASSWORD": body.get("smtp_password"), "SMTP_FROM": body.get("smtp_from"), "SMTP_TLS": body.get("smtp_tls"), "SMTP_SSL": body.get("smtp_ssl"), } for env_key, raw in mapping.items(): if raw is None: continue if env_key in BOOL_ENV_KEYS: if isinstance(raw, bool): updates[env_key] = "true" if raw else "false" else: updates[env_key] = ( "true" if str(raw).strip().lower() in {"1", "true", "yes", "on"} else "false" ) continue text = str(raw).strip() if env_key in SECRET_ENV_KEYS: if text == "__clear__": updates[env_key] = None elif _is_masked_placeholder(text): continue else: updates[env_key] = text continue updates[env_key] = text if text else None if updates: upsert_env_keys(updates, allowlist=SMTP_ENV_KEYS) return get_settings(require_bot_token=False)