"""Cambia la contrasena de un usuario en la API de administracion de Popelis.""" import json import urllib.error import urllib.request def popelis_set_password( base_url: str, admin_token: str, username: str, password: str, timeout: float = 30.0, ) -> dict: """Cambia la contrasena de un usuario existente en Popelis. Hace POST a {base_url}/api/admin/users/password con el token de admin, el nombre de usuario y la nueva contrasena. Devuelve 404 si el usuario no existe. Args: base_url: URL base del servicio, sin trailing slash. Ej: "https://popelis.datardos.com" admin_token: Token de administracion (cabecera X-Admin-Token). Mantenerlo en secreto — no logear. username: Nombre de usuario cuya contrasena se quiere cambiar. password: Nueva contrasena a establecer. timeout: Timeout en segundos para la peticion HTTP. Default 30.0. Returns: Dict con el resultado: {"status": "password updated"} Raises: ValueError: Si el servidor devuelve 4xx o 5xx (incluyendo 404 cuando el usuario no existe). El mensaje incluye el status code y el campo "error" del body JSON si existe. urllib.error.URLError: Si no se puede conectar al servidor. """ url = f"{base_url.rstrip('/')}/api/admin/users/password" payload = json.dumps({"username": username, "password": password}).encode("utf-8") req = urllib.request.Request( url, data=payload, headers={ "Content-Type": "application/json", "X-Admin-Token": admin_token, }, method="POST", ) try: with urllib.request.urlopen(req, timeout=timeout) as resp: body = resp.read() return json.loads(body) except urllib.error.HTTPError as exc: raw = exc.read() try: detail = json.loads(raw).get("error", raw.decode("utf-8", errors="replace")) except Exception: detail = raw.decode("utf-8", errors="replace") if exc.code == 404: raise ValueError( f"popelis_set_password: usuario '{username}' no existe (HTTP 404) — {detail}" ) from exc raise ValueError( f"popelis_set_password: HTTP {exc.code} — {detail}" ) from exc