Coverage for src/qdrant_loader/connectors/confluence/config.py: 90%
50 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-04 05:50 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-04 05:50 +0000
1"""Configuration for Confluence connector."""
3import os
4from enum import Enum
5from typing import Self
7from pydantic import ConfigDict, Field, field_validator, model_validator
9from qdrant_loader.config.source_config import SourceConfig
12class ConfluenceDeploymentType(str, Enum):
13 """Confluence deployment types."""
15 CLOUD = "cloud"
16 DATACENTER = "datacenter"
17 SERVER = "server" # Legacy, treated same as datacenter
20class ConfluenceSpaceConfig(SourceConfig):
21 """Configuration for a Confluence space."""
23 model_config = ConfigDict(arbitrary_types_allowed=True)
25 space_key: str = Field(..., description="Key of the Confluence space")
26 content_types: list[str] = Field(
27 default=["page", "blogpost"], description="Types of content to process"
28 )
29 deployment_type: ConfluenceDeploymentType = Field(
30 default=ConfluenceDeploymentType.CLOUD,
31 description="Confluence deployment type (cloud, datacenter, or server)",
32 )
33 token: str | None = Field(
34 ..., description="Confluence API token or Personal Access Token"
35 )
36 email: str | None = Field(
37 default=None,
38 description="Email associated with the Confluence account (Cloud only)",
39 )
41 include_labels: list[str] = Field(
42 default=[],
43 description="List of labels to include (empty list means include all)",
44 )
45 exclude_labels: list[str] = Field(
46 default=[], description="List of labels to exclude"
47 )
49 @field_validator("content_types")
50 @classmethod
51 def validate_content_types(cls, v: list[str]) -> list[str]:
52 """Validate content types."""
53 valid_types = ["page", "blogpost", "comment"]
54 for content_type in v:
55 if content_type.lower() not in valid_types:
56 raise ValueError(f"Content type must be one of {valid_types}")
57 return [t.lower() for t in v]
59 @field_validator("deployment_type", mode="before")
60 @classmethod
61 def auto_detect_deployment_type(
62 cls, v: str | ConfluenceDeploymentType
63 ) -> ConfluenceDeploymentType:
64 """Auto-detect deployment type if not specified."""
65 if isinstance(v, str):
66 return ConfluenceDeploymentType(v.lower())
67 return v
69 @field_validator("token", mode="after")
70 @classmethod
71 def load_token_from_env(cls, v: str | None) -> str | None:
72 """Load token from environment variable if not provided."""
73 return v or os.getenv("CONFLUENCE_TOKEN")
75 @field_validator("email", mode="after")
76 @classmethod
77 def load_email_from_env(cls, v: str | None) -> str | None:
78 """Load email from environment variable if not provided."""
79 return v or os.getenv("CONFLUENCE_EMAIL")
81 @model_validator(mode="after")
82 def validate_auth_config(self) -> Self:
83 """Validate authentication configuration based on deployment type."""
84 if self.deployment_type == ConfluenceDeploymentType.CLOUD:
85 # Cloud requires email and token
86 if not self.email:
87 raise ValueError("Email is required for Confluence Cloud deployment")
88 if not self.token:
89 raise ValueError(
90 "API token is required for Confluence Cloud deployment"
91 )
92 else:
93 # Data Center/Server requires Personal Access Token
94 if not self.token:
95 raise ValueError(
96 "Personal Access Token is required for Confluence Data Center/Server deployment"
97 )
99 return self