Skip to content

Commit 5be6f66

Browse files
committed
fixes found with mcp server testing
Core architectural fix where wrapper clients now properly delegate to underlying raw clients instead of reimplementing functionality. Adds missing search() method to AlfrescoSearchClient wrapper. Includes post-processed models and updated examples for wrapper integration. Resolves import naming consistency (SQL vs Sql). All manual work preserved (docs, events).
1 parent 78dde47 commit 5be6f66

20 files changed

+263
-448
lines changed

python_alfresco_api/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
# Individual clients
1818
from .clients.auth_client import AlfrescoAuthClient
19-
from .clients.core_client import AlfrescoCoreClient
19+
from .clients.core_client import AlfrescoCoreClient
2020
from .clients.discovery_client import AlfrescoDiscoveryClient
2121
from .clients.search_client import AlfrescoSearchClient
2222
from .clients.workflow_client import AlfrescoWorkflowClient
@@ -31,13 +31,13 @@
3131
# Factory & utilities
3232
"ClientFactory",
3333
"AuthUtil",
34-
34+
3535
# Individual clients
3636
"AlfrescoAuthClient",
37-
"AlfrescoCoreClient",
37+
"AlfrescoCoreClient",
3838
"AlfrescoDiscoveryClient",
3939
"AlfrescoSearchClient",
40-
"AlfrescoWorkflowClient",
40+
"AlfrescoWorkflowClient",
4141
"AlfrescoModelClient",
4242
"AlfrescoSearchSQLClient"
4343
]

python_alfresco_api/auth_util.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
Handles ticket-based authentication with automatic renewal.
66
"""
77

8+
import asyncio
9+
from typing import Optional, Dict, Any
810
from datetime import datetime, timedelta
9-
from typing import Dict
1011

1112
class AuthUtil:
1213
"""
1314
Shared authentication utility for Alfresco APIs.
14-
15+
1516
Handles ticket-based authentication with automatic renewal.
1617
Can be shared across multiple API clients.
1718
"""
18-
19+
1920
def __init__(
2021
self,
2122
base_url: str,
@@ -26,7 +27,7 @@ def __init__(
2627
):
2728
"""
2829
Initialize authentication utility.
29-
30+
3031
Args:
3132
base_url: Base URL of Alfresco instance
3233
username: Alfresco username
@@ -39,64 +40,64 @@ def __init__(
3940
self.password = password
4041
self.verify_ssl = verify_ssl
4142
self.timeout = timeout
42-
43+
4344
self.ticket = None
4445
self.ticket_expires = None
4546
self._authenticated = False
46-
47+
4748
async def authenticate(self) -> bool:
4849
"""
4950
Authenticate with Alfresco and get ticket.
50-
51+
5152
Returns:
5253
True if authentication successful, False otherwise
5354
"""
5455
try:
5556
# Import here to avoid circular imports
5657
from .clients.auth_client import AlfrescoAuthClient
5758
from .models.alfresco_auth_models import TicketBody
58-
59+
5960
auth_client = AlfrescoAuthClient(self.base_url, None, self.verify_ssl, self.timeout)
60-
61+
6162
ticket_body = TicketBody(userId=self.username, password=self.password)
6263
ticket_response = await auth_client.create_ticket(ticket_body)
63-
64+
6465
if ticket_response and hasattr(ticket_response, 'entry'):
6566
self.ticket = ticket_response.entry.id
6667
# Tickets typically expire after 1 hour
6768
self.ticket_expires = datetime.now() + timedelta(hours=1)
6869
self._authenticated = True
6970
return True
70-
71+
7172
except Exception as e:
7273
print(f"Authentication failed: {e}")
7374
self._authenticated = False
74-
75+
7576
return False
76-
77+
7778
def is_authenticated(self) -> bool:
7879
"""Check if currently authenticated with valid ticket"""
7980
if not self._authenticated or not self.ticket:
8081
return False
81-
82+
8283
if self.ticket_expires and datetime.now() >= self.ticket_expires:
8384
self._authenticated = False
8485
return False
85-
86+
8687
return True
87-
88+
8889
def get_auth_headers(self) -> Dict[str, str]:
8990
"""Get authentication headers for API requests"""
9091
if not self.is_authenticated():
9192
return {}
92-
93+
9394
return {
9495
"X-Alfresco-Ticket": self.ticket
9596
}
96-
97+
9798
async def ensure_authenticated(self) -> bool:
9899
"""Ensure we have valid authentication, refresh if needed"""
99100
if self.is_authenticated():
100101
return True
101-
102+
102103
return await self.authenticate()

python_alfresco_api/client_factory.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
class ClientFactory:
1919
"""
2020
Factory for creating Alfresco API clients.
21-
21+
2222
Supports both individual client creation and shared authentication.
2323
"""
24-
24+
2525
def __init__(
2626
self,
2727
base_url: str,
@@ -32,51 +32,51 @@ def __init__(
3232
):
3333
"""
3434
Initialize the client factory.
35-
35+
3636
Args:
3737
base_url: Base URL of Alfresco instance
3838
username: Optional username for authentication
39-
password: Optional password for authentication
39+
password: Optional password for authentication
4040
verify_ssl: Whether to verify SSL certificates
4141
timeout: Request timeout in seconds
4242
"""
4343
self.base_url = base_url
4444
self.verify_ssl = verify_ssl
4545
self.timeout = timeout
46-
46+
4747
# Initialize auth utility if credentials provided
4848
self.auth = None
4949
if username and password:
5050
self.auth = AuthUtil(base_url, username, password, verify_ssl, timeout)
51-
51+
5252
def create_auth_client(self) -> AlfrescoAuthClient:
5353
"""Create Authentication API client"""
5454
return AlfrescoAuthClient(self.base_url, self.auth, self.verify_ssl, self.timeout)
55-
55+
5656
def create_core_client(self) -> AlfrescoCoreClient:
5757
"""Create Core API client"""
5858
return AlfrescoCoreClient(self.base_url, self.auth, self.verify_ssl, self.timeout)
59-
59+
6060
def create_discovery_client(self) -> AlfrescoDiscoveryClient:
6161
"""Create Discovery API client"""
6262
return AlfrescoDiscoveryClient(self.base_url, self.auth, self.verify_ssl, self.timeout)
63-
63+
6464
def create_search_client(self) -> AlfrescoSearchClient:
6565
"""Create Search API client"""
6666
return AlfrescoSearchClient(self.base_url, self.auth, self.verify_ssl, self.timeout)
67-
67+
6868
def create_workflow_client(self) -> AlfrescoWorkflowClient:
6969
"""Create Workflow API client"""
7070
return AlfrescoWorkflowClient(self.base_url, self.auth, self.verify_ssl, self.timeout)
71-
71+
7272
def create_model_client(self) -> AlfrescoModelClient:
7373
"""Create Model API client"""
7474
return AlfrescoModelClient(self.base_url, self.auth, self.verify_ssl, self.timeout)
75-
75+
7676
def create_search_sql_client(self) -> AlfrescoSearchSQLClient:
7777
"""Create Search SQL API client"""
7878
return AlfrescoSearchSQLClient(self.base_url, self.auth, self.verify_ssl, self.timeout)
79-
79+
8080
def create_all_clients(self) -> Dict[str, Any]:
8181
"""Create all available clients"""
8282
return {

python_alfresco_api/clients/auth_client.py

Lines changed: 10 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
class AlfrescoAuthClient:
2424
"""
2525
Individual client for Alfresco AUTH API.
26-
26+
2727
Features:
2828
- Uses generated HTTP client internally
2929
- Automatic authentication with AuthUtil
3030
- Pydantic model integration
3131
- Both sync and async methods
3232
"""
33-
33+
3434
def __init__(
3535
self,
3636
base_url: str,
@@ -40,7 +40,7 @@ def __init__(
4040
):
4141
"""
4242
Initialize auth client.
43-
43+
4444
Args:
4545
base_url: Base URL of Alfresco instance
4646
auth_util: Optional AuthUtil instance for authentication
@@ -51,11 +51,11 @@ def __init__(
5151
self.auth_util = auth_util
5252
self.verify_ssl = verify_ssl
5353
self.timeout = timeout
54-
54+
5555
# Initialize the generated client
5656
self._init_generated_client()
57-
58-
def _init_generated_client(self) -> None:
57+
58+
def _init_generated_client(self):
5959
"""Initialize the generated HTTP client"""
6060
try:
6161
from client import Client
@@ -65,56 +65,16 @@ def _init_generated_client(self) -> None:
6565
print(f"⚠️ Generated client not available for auth: {e}")
6666
self.client = None
6767
self._client_available = False
68-
68+
6969
def is_available(self) -> bool:
7070
"""Check if the generated client is available"""
7171
return self._client_available
72-
73-
async def _ensure_auth(self) -> None:
72+
73+
async def _ensure_auth(self):
7474
"""Ensure authentication before API calls"""
7575
if self.auth_util:
7676
await self.auth_util.ensure_authenticated()
77-
78-
async def create_ticket(self, ticket_body) -> Any:
79-
"""Create authentication ticket"""
80-
if not self._client_available:
81-
# Simplified mock response for when client isn't available
82-
print("⚠️ Auth client not fully initialized - using basic auth")
83-
return type('MockTicketResponse', (), {
84-
'entry': type('Entry', (), {'id': 'mock-ticket-basic-auth'})()
85-
})()
86-
87-
try:
88-
# Try to use the actual generated client
89-
import httpx
90-
91-
# Build request directly
92-
url = f"{self.base_url}/alfresco/api/-default-/public/authentication/versions/1/tickets"
93-
94-
# Convert ticket_body to dict
95-
if hasattr(ticket_body, 'model_dump'):
96-
data = ticket_body.model_dump()
97-
elif hasattr(ticket_body, 'dict'):
98-
data = ticket_body.dict()
99-
else:
100-
data = ticket_body
101-
102-
async with httpx.AsyncClient(verify=self.verify_ssl, timeout=self.timeout) as client:
103-
response = await client.post(url, json=data)
104-
105-
if response.status_code == 201:
106-
result = response.json()
107-
return type('TicketResponse', (), {
108-
'entry': type('Entry', (), {'id': result.get('entry', {}).get('id', 'no-ticket')})()
109-
})()
110-
else:
111-
print(f"⚠️ Auth request failed with status {response.status_code}")
112-
return None
113-
114-
except Exception as e:
115-
print(f"⚠️ Auth fallback: {e}")
116-
return None
117-
77+
11878
def get_client_info(self) -> Dict[str, Any]:
11979
"""Get information about this client"""
12080
return {

python_alfresco_api/clients/core_client.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
class AlfrescoCoreClient:
2424
"""
2525
Individual client for Alfresco CORE API.
26-
26+
2727
Features:
2828
- Uses generated HTTP client internally
2929
- Automatic authentication with AuthUtil
3030
- Pydantic model integration
3131
- Both sync and async methods
3232
"""
33-
33+
3434
def __init__(
3535
self,
3636
base_url: str,
@@ -40,7 +40,7 @@ def __init__(
4040
):
4141
"""
4242
Initialize core client.
43-
43+
4444
Args:
4545
base_url: Base URL of Alfresco instance
4646
auth_util: Optional AuthUtil instance for authentication
@@ -51,11 +51,11 @@ def __init__(
5151
self.auth_util = auth_util
5252
self.verify_ssl = verify_ssl
5353
self.timeout = timeout
54-
54+
5555
# Initialize the generated client
5656
self._init_generated_client()
57-
58-
def _init_generated_client(self) -> None:
57+
58+
def _init_generated_client(self):
5959
"""Initialize the generated HTTP client"""
6060
try:
6161
from client import Client
@@ -65,16 +65,16 @@ def _init_generated_client(self) -> None:
6565
print(f"⚠️ Generated client not available for core: {e}")
6666
self.client = None
6767
self._client_available = False
68-
68+
6969
def is_available(self) -> bool:
7070
"""Check if the generated client is available"""
7171
return self._client_available
72-
73-
async def _ensure_auth(self) -> None:
72+
73+
async def _ensure_auth(self):
7474
"""Ensure authentication before API calls"""
7575
if self.auth_util:
7676
await self.auth_util.ensure_authenticated()
77-
77+
7878
def get_client_info(self) -> Dict[str, Any]:
7979
"""Get information about this client"""
8080
return {

0 commit comments

Comments
 (0)