""" Cliente WebDAV para Nextcloud. Provee métodos para interactuar con Nextcloud via WebDAV. """ import logging from pathlib import Path from typing import Optional from webdav3.client import Client from config import settings class WebDAVService: """Cliente WebDAV para Nextcloud.""" def __init__(self) -> None: self.logger = logging.getLogger(__name__) self._client: Optional[Client] = None def _get_client(self) -> Client: """Obtiene o crea el cliente WebDAV.""" if self._client is None: if not settings.has_webdav_config: raise RuntimeError("WebDAV configuration missing") options = { "webdav_hostname": settings.NEXTCLOUD_URL, "webdav_login": settings.NEXTCLOUD_USER, "webdav_password": settings.NEXTCLOUD_PASSWORD, } self._client = Client(options) self._client.verify = True # Verificar SSL return self._client def test_connection(self) -> bool: """Prueba la conexión con Nextcloud.""" try: client = self._get_client() return client.check() except Exception as e: self.logger.error(f"WebDAV connection failed: {e}") return False def list_files(self, remote_path: str = "/") -> list[str]: """Lista archivos en una ruta remota.""" try: client = self._get_client() # Asegurar que la ruta empieza con / if not remote_path.startswith("/"): remote_path = "/" + remote_path files = client.list(remote_path) return files if files else [] except Exception as e: self.logger.error(f"Failed to list files: {e}") return [] def download_file(self, remote_path: str, local_path: Path) -> bool: """Descarga un archivo desde Nextcloud.""" try: client = self._get_client() local_path.parent.mkdir(parents=True, exist_ok=True) client.download_sync(remote_path=str(remote_path), local_path=str(local_path)) self.logger.info(f"Downloaded: {remote_path} -> {local_path}") return True except Exception as e: self.logger.error(f"Failed to download {remote_path}: {e}") return False def get_file_info(self, remote_path: str) -> dict: """Obtiene información de un archivo.""" try: client = self._get_client() info = client.info(remote_path) return { "name": info.get("name", ""), "size": info.get("size", 0), "modified": info.get("modified", ""), } except Exception as e: self.logger.error(f"Failed to get file info: {e}") return {} def file_exists(self, remote_path: str) -> bool: """Verifica si un archivo existe en remoto.""" try: client = self._get_client() return client.check(remote_path) except Exception: return False def upload_file(self, local_path: Path, remote_path: str) -> bool: """Sube un archivo a Nextcloud.""" try: client = self._get_client() client.upload_sync(local_path=str(local_path), remote_path=str(remote_path)) self.logger.info(f"Uploaded: {local_path} -> {remote_path}") return True except Exception as e: self.logger.error(f"Failed to upload {local_path}: {e}") return False