# Copyright (c) 2025 Patrick Motsch # All rights reserved. """Abstract base classes for the Provider-Connector architecture (1:n). One ProviderConnector per vendor (e.g. MsftConnector, GoogleConnector). Each ProviderConnector exposes n ServiceAdapters (e.g. SharepointAdapter, OutlookAdapter). All ServiceAdapters share the same access token from the UserConnection. """ from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import List, Optional, Union @dataclass class DownloadResult: """Rich return type for ServiceAdapter.download() when metadata is available.""" data: bytes = field(default=b"", repr=False) fileName: str = "" mimeType: str = "" class ServiceAdapter(ABC): """Standardized operations for a single service of a provider.""" @abstractmethod async def browse(self, path: str, filter: Optional[str] = None) -> list: """List items (files/folders) at the given path.""" ... @abstractmethod async def download(self, path: str) -> Union[bytes, DownloadResult]: """Download a file. Return bytes or DownloadResult with metadata.""" ... @abstractmethod async def upload(self, path: str, data: bytes, fileName: str) -> dict: """Upload a file to the given path. Returns metadata of the created entry.""" ... @abstractmethod async def search(self, query: str, path: Optional[str] = None) -> list: """Search for items matching the query.""" ... class ProviderConnector(ABC): """One connector per provider. Manages a UserConnection + token. Provides access to n services of the provider.""" def __init__(self, connection, accessToken: str): self.connection = connection self.accessToken = accessToken @abstractmethod def getAvailableServices(self) -> List[str]: """Which services does this provider offer?""" ... @abstractmethod def getServiceAdapter(self, service: str) -> ServiceAdapter: """Return the ServiceAdapter for a specific service.""" ...