initial working state

This commit is contained in:
Hirad 2025-07-16 15:09:41 +03:30
parent 816fb34f75
commit bb9a24c1ed
15 changed files with 688 additions and 0 deletions

View file

@ -0,0 +1,83 @@
from dataclasses import dataclass, field
from typing import Dict, Set, Union
from urllib.parse import urlparse
@dataclass
class SynapseConfig:
"""Store and validate configuration for Synapse API connection."""
homeserver: str
access_token: str
blacklist: Set[str] = field(default_factory=set)
def __post_init__(self) -> None:
"""Validate Synapse config after initialization."""
if not self.homeserver.strip():
raise ValueError("Homeserver URL cannot be empty")
parsed = urlparse(self.homeserver)
if not all([parsed.scheme, parsed.netloc]):
raise ValueError(f"Invalid homeserver URL: {self.homeserver}")
if not self.access_token.strip():
raise ValueError("Access token cannot be empty")
if not isinstance(self.blacklist, set):
raise TypeError("Blacklist must be a set")
for username in self.blacklist:
if not isinstance(username, str) or not username.strip():
raise ValueError("Blacklist contains invalid username")
@property
def base_url(self) -> str:
"""Get normalized base URL with trailing slash."""
return self.homeserver.rstrip('/') + '/_synapse/admin'
@property
def headers(self) -> Dict[str, str]:
"""Generate request headers with authentication."""
return {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json",
"Accept": "application/json"
}
def add_to_blacklist(self, *usernames: str) -> None:
"""Add one or more username to the blacklist."""
for username in usernames:
username = username.strip()
if not username:
raise ValueError("Username cannot be empty")
self.blacklist.add(username)
def remove_from_blacklist(self, *usernames: str) -> None:
"""Remove one or more username from the blacklist."""
for username in usernames:
self.blacklist.discard(username)
@classmethod
def from_dict(cls, data: Dict[str, str]) -> "SynapseConfig":
"""Create from dictionary with validation."""
try:
blacklist = set(data.get("blacklist", []))
return cls(
homeserver=str(data["homeserver"]),
access_token=str(data["access_token"]),
blacklist=blacklist
)
except KeyError as e:
raise ValueError(f"Missing required field: {e}") from e
except (TypeError, ValueError) as e:
raise ValueError(f"Invalid data type: {e}") from e
def to_dict(self) -> Dict[str, Union[str, Set[str]]]:
"""Serialize to dictionary without sensitive exposure."""
return {
"homeserver": self.homeserver,
"access_token": self.access_token,
"blacklist": sorted(self.blacklist)
}
def __str__(self) -> str:
"""Safe representation excluding access token."""
return (f"SynapseConfig(homeserver={self.homeserver!r},"
f"blacklist={len(self.blacklist)})")