refactor: switch Wiki.js client to API token authentication

Replace username/password login flow with simpler API token auth:
- Use WIKI_GRAPHQL_API environment variable for JWT token
- Remove login() method and session management
- Add list_pages() method for fetching all pages
- Keep legacy auth fields in config for backwards compatibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-24 16:21:39 +01:00
co-authored by Claude Opus 4.5
parent 318636d33d
commit 9446d6bf9a
+12 -77
View File
@@ -20,96 +20,31 @@ class WikiJSClient:
Wiki.js GraphQL API client.
Documentation: https://docs.requarks.io/dev/api
Authentication: Username/password login to get user-specific JWT token
Authentication: API token (JWT) generated from Wiki.js admin panel
"""
def __init__(self, base_url: str, username: str, password: str):
def __init__(self, base_url: str, api_token: str):
"""
Initialize Wiki.js client.
Args:
base_url: Wiki.js base URL (e.g., "http://wiki:3000")
username: Wiki.js username (e.g., "librarian@schweitz.net")
password: Wiki.js password
api_token: Wiki.js API token (JWT from admin panel)
"""
self.base_url = base_url.rstrip("/")
self.graphql_url = f"{self.base_url}/graphql"
self.username = username
self.password = password
self.jwt_token: Optional[str] = None
self.api_token = api_token
self.client = httpx.AsyncClient(timeout=30.0)
logger.info(f"Initialized Wiki.js client: {base_url} (user: {username})")
logger.info(f"Initialized Wiki.js client: {base_url} (using API token)")
async def close(self):
"""Close HTTP client"""
await self.client.aclose()
async def login(self) -> bool:
"""
Authenticate with Wiki.js using username/password.
Returns:
True if login successful, False otherwise
"""
login_mutation = """
mutation Login($username: String!, $password: String!, $strategy: String!) {
authentication {
login(username: $username, password: $password, strategy: $strategy) {
responseResult {
succeeded
errorCode
message
}
jwt
}
}
}
"""
variables = {
"username": self.username,
"password": self.password,
"strategy": "local"
}
try:
response = await self.client.post(
self.graphql_url,
headers={"Content-Type": "application/json"},
json={"query": login_mutation, "variables": variables}
)
response.raise_for_status()
result = response.json()
if "errors" in result:
logger.error(f"Login failed: {result['errors']}")
return False
login_result = result.get("data", {}).get("authentication", {}).get("login", {})
response_result = login_result.get("responseResult", {})
if not response_result.get("succeeded"):
logger.error(f"Login failed: {response_result.get('message')}")
return False
self.jwt_token = login_result.get("jwt")
if not self.jwt_token:
logger.error("Login succeeded but no JWT token received")
return False
logger.info(f"Successfully authenticated as {self.username}")
return True
except Exception as e:
logger.error(f"Login failed: {e}", exc_info=True)
return False
async def _ensure_authenticated(self):
"""Ensure we have a valid JWT token, login if needed."""
if not self.jwt_token:
success = await self.login()
if not success:
raise Exception("Failed to authenticate with Wiki.js")
def _ensure_authenticated(self):
"""Verify API token is configured."""
if not self.api_token:
raise Exception("Wiki.js API token not configured")
async def _execute_query(
self,
@@ -129,8 +64,8 @@ class WikiJSClient:
Raises:
Exception: If query fails or returns errors
"""
# Ensure we're authenticated before making requests
await self._ensure_authenticated()
# Ensure API token is configured
self._ensure_authenticated()
payload = {
"query": query,
@@ -138,7 +73,7 @@ class WikiJSClient:
}
headers = {
"Authorization": f"Bearer {self.jwt_token}",
"Authorization": f"Bearer {self.api_token}",
"Content-Type": "application/json"
}