from __future__ import annotations from app.core.errors import ConflictError, ValidationAppError from app.integrations.repository import IntegrationRepository, IntegrationSettingsRecord from app.integrations.schemas import IntegrationUpdate, IntegrationView, SecretFlags class IntegrationService: def __init__(self, repository: IntegrationRepository) -> None: self.repository = repository def get_view(self) -> IntegrationView: record = self.repository.get() return IntegrationView( config_version=record.config_version, use_default_aws_credentials=record.use_default_aws_credentials, secrets_configured=SecretFlags(**self.repository.secret_flags()), ) def update(self, payload: IntegrationUpdate) -> IntegrationView: flags = self.repository.secret_flags() if not payload.use_default_aws_credentials: has_pair = bool(payload.aws_access_key_id and payload.aws_secret_access_key) or ( flags["aws_access_key_id"] and flags["aws_secret_access_key"] ) if not has_pair: raise ValidationAppError("请填写 AWS API 密钥,或选择默认凭据链") if not payload.cloudflare_api_token and not flags["cloudflare_api_token"]: raise ValidationAppError("请填写 Cloudflare API Token") try: self.repository.save( payload.use_default_aws_credentials, { "aws_access_key_id": payload.aws_access_key_id, "aws_secret_access_key": payload.aws_secret_access_key, "aws_session_token": payload.aws_session_token, "cloudflare_api_token": payload.cloudflare_api_token, }, ) except RuntimeError as exc: code = str(exc) if code == "ACTIVE_ROTATION": raise ConflictError( "轮换任务进行中,暂时不能修改共享凭据", code="ROTATION_IN_PROGRESS", ) from exc if code == "ACTIVE_ROTATION_CONFIG_CHANGE": raise ConflictError( "待处理任务只允许替换密钥,不能切换 AWS 凭据模式", code="RECOVERY_MODE_CHANGE_BLOCKED", ) from exc if code == "RECOVERY_SECRET_REQUIRED": raise ValidationAppError("请至少填写一项需要替换的恢复凭据") from exc raise return self.get_view() def credentials(self) -> tuple[IntegrationSettingsRecord, dict[str, str | None]]: return self.repository.get(), self.repository.get_secrets() def ensure_configured(self) -> None: settings, secrets = self.credentials() if not settings.use_default_aws_credentials and not ( secrets.get("aws_access_key_id") and secrets.get("aws_secret_access_key") ): raise ValidationAppError("当前没有可用的 AWS 凭据") if not secrets.get("cloudflare_api_token"): raise ValidationAppError("当前没有可用的 Cloudflare API Token")