|
|
# backend/app/connectors/registry.py — CONNECTOR_<DOMAIN> 로 mock|real 선택하는 단일 지점.
|
|
|
# 페이지/라우터는 항상 레지스트리를 통해서만 sync 커넥터를 얻는다(코드 불변의 핵심).
|
|
|
from sqlmodel import Session, select
|
|
|
|
|
|
from ..config import get_settings
|
|
|
from ..models import ConnectorAccount
|
|
|
from .base import BaseConnector
|
|
|
|
|
|
|
|
|
def _impl(domain: str, mode: str, provider: str = ""):
|
|
|
"""도메인 × 모드 → 구현 클래스 (lazy import 로 의존성 격리)."""
|
|
|
if domain == "mail": # mock 제거(phase-16+): 실 계정만 동기화
|
|
|
if mode == "real": # real 메일은 provider 로 Gmail/Outlook 분기
|
|
|
from .mail.real_gmail import GmailConnector
|
|
|
from .mail.real_outlook import OutlookConnector
|
|
|
|
|
|
return OutlookConnector if provider == "outlook" else GmailConnector
|
|
|
if mode == "imap":
|
|
|
from .mail.real_imap import ImapConnector
|
|
|
|
|
|
return ImapConnector
|
|
|
raise ValueError(f"unsupported mail connector mode: {mode}")
|
|
|
if domain == "calendar": # mock 제거(phase-16+)
|
|
|
if mode == "real": # real 캘린더는 provider 로 Google/Outlook 분기
|
|
|
if provider == "outlook_calendar":
|
|
|
from .calendar.real_outlook import OutlookCalendarConnector
|
|
|
|
|
|
return OutlookCalendarConnector
|
|
|
from .calendar.real_google import GoogleCalendarConnector
|
|
|
|
|
|
return GoogleCalendarConnector
|
|
|
if mode == "ics":
|
|
|
from .calendar.ics_import import IcsConnector
|
|
|
|
|
|
return IcsConnector
|
|
|
raise ValueError(f"unsupported calendar connector mode: {mode}")
|
|
|
raise ValueError(f"unknown domain {domain}")
|
|
|
|
|
|
|
|
|
class ConnectorRegistry:
|
|
|
@staticmethod
|
|
|
def mode_for(domain) -> str:
|
|
|
dom = domain.value if hasattr(domain, "value") else str(domain)
|
|
|
return getattr(get_settings(), f"connector_{dom}", "mock")
|
|
|
|
|
|
@staticmethod
|
|
|
def effective_mode(account: ConnectorAccount) -> str:
|
|
|
"""모드 결정 정본:
|
|
|
- 계정 mode 가 mock 이 아니면(real/csv/healthkit/ics) 그 모드를 쓴다(연결된 계정).
|
|
|
- 시드 mock 계정은 env=real 이어도 mock 유지(데모 결정성).
|
|
|
- csv/healthkit/ics env 면 그 모드를 따른다(로컬 우선 임포트)."""
|
|
|
env_mode = ConnectorRegistry.mode_for(account.domain)
|
|
|
acct_mode = account.mode.value if hasattr(account.mode, "value") else str(account.mode)
|
|
|
if acct_mode != "mock":
|
|
|
return acct_mode
|
|
|
return "mock" if env_mode == "real" else env_mode
|
|
|
|
|
|
@staticmethod
|
|
|
def get(session: Session, account: ConnectorAccount) -> BaseConnector:
|
|
|
mode = ConnectorRegistry.effective_mode(account)
|
|
|
dom = account.domain.value if hasattr(account.domain, "value") else account.domain
|
|
|
return _impl(dom, mode, account.provider)(account)
|
|
|
|
|
|
@staticmethod
|
|
|
def accounts(session: Session, domain: str | None = None) -> list[ConnectorAccount]:
|
|
|
q = select(ConnectorAccount)
|
|
|
if domain:
|
|
|
q = q.where(ConnectorAccount.domain == domain)
|
|
|
return session.exec(q.order_by(ConnectorAccount.id)).all()
|