from abc import ABC, abstractmethod import structlog logger = structlog.get_logger(__name__) class InvoiceRepository(ABC): @abstractmethod def upload_invoice(self, invoice: str, filename: str): pass class SFTPInvoiceRepository(InvoiceRepository): def __init__(self, hostname: str, username: str, password: str, port: int = 22): self.hostname = hostname self.username = username self.password = password self.port = port def upload_invoice(self, invoice: str, filename: str) -> None: from io import BytesIO from paramiko import AutoAddPolicy, SSHClient invoice_io = BytesIO(invoice.encode("utf-8")) ssh_client = SSHClient() try: ssh_client.set_missing_host_key_policy(AutoAddPolicy()) ssh_client.connect( self.hostname, port=self.port, username=self.username, password=self.password, ) with ssh_client.open_sftp() as sftp_client: sftp_client.putfo(invoice_io, f"uploads/{filename}") except Exception as e: logger.error("Could not upload invoice", exc_info=e) finally: ssh_client.close()