diff --git a/test_api_connection.py b/test_api_connection.py index fea2dad..8d5ed19 100644 --- a/test_api_connection.py +++ b/test_api_connection.py @@ -5,6 +5,7 @@ import os import sys import asyncio import aiohttp +import json from dotenv import load_dotenv # Load environment variables @@ -28,20 +29,18 @@ async def test_dolibarr_connection(): print(" Please set DOLIBARR_URL and DOLIBARR_API_KEY in .env file") return False - # Ensure URL format is correct - if not base_url.endswith('/api/index.php'): - if base_url.endswith('/'): - base_url = base_url + 'api/index.php' - else: - base_url = base_url + '/api/index.php' + # Clean base URL - remove trailing slash if present + base_url = base_url.rstrip('/') # Test different endpoints endpoints_to_test = [ - "/status", - "/explorer/swagger", # Swagger documentation - "/setup/modules", # Module list - "/users", # Users list - "/thirdparties", # Customers/Suppliers + "status", # API status + "users", # Users list + "thirdparties", # Customers/Suppliers + "products", # Products + "invoices", # Invoices + "orders", # Orders + "contacts", # Contacts ] # Headers for Dolibarr API @@ -54,112 +53,173 @@ async def test_dolibarr_connection(): print("๐Ÿงช Testing Dolibarr API endpoints:") print("=" * 50) + working_endpoints = [] + async with aiohttp.ClientSession() as session: for endpoint in endpoints_to_test: - # Clean endpoint - endpoint = endpoint.lstrip('/') + url = f"{base_url}/{endpoint}" - # Build full URL - if endpoint in ["status", "explorer/swagger"]: - # These endpoints might be at root level - test_urls = [ - f"{base_url}/{endpoint}", - f"{base_url.replace('/api/index.php', '')}/{endpoint}", - f"{base_url.replace('/api/index.php', '/api')}/{endpoint}" - ] - else: - test_urls = [f"{base_url}/{endpoint}"] - - success = False - for url in test_urls: - try: - print(f"\n๐Ÿ“ Testing: {url}") + try: + print(f"\n๐Ÿ“ Testing: {endpoint}") + print(f" URL: {url}") + + async with session.get(url, headers=headers, timeout=10, ssl=False) as response: + status = response.status + text = await response.text() - async with session.get(url, headers=headers, timeout=10) as response: - status = response.status - text = await response.text() - - print(f" Status: {status}") - - if status == 200: - print(f" โœ… Success!") - if text: - # Try to parse response - try: - import json - data = json.loads(text) - if isinstance(data, dict): - print(f" Response keys: {list(data.keys())[:5]}") - elif isinstance(data, list): - print(f" Response: List with {len(data)} items") - except: - print(f" Response preview: {text[:100]}...") - success = True - break - elif status == 401: - print(f" โŒ Authentication failed - check API key") - elif status == 403: - print(f" โŒ Access forbidden - check permissions") - elif status == 404: - print(f" โŒ Endpoint not found") - else: - print(f" โš ๏ธ Unexpected status: {status}") + print(f" Status: {status}") + + if status == 200: + print(f" โœ… Success!") + working_endpoints.append(endpoint) + try: + data = json.loads(text) + if isinstance(data, dict): + print(f" Response keys: {list(data.keys())[:5]}") + elif isinstance(data, list): + print(f" Response: List with {len(data)} items") + if len(data) > 0 and isinstance(data[0], dict): + print(f" First item keys: {list(data[0].keys())[:5]}") + except: + print(f" Response preview: {text[:100]}...") + elif status == 401: + print(f" โŒ Authentication failed - check API key") + elif status == 403: + print(f" โŒ Access forbidden - check permissions") + elif status == 404: + print(f" โŒ Endpoint not found") + elif status == 501: + print(f" โš ๏ธ API module not found - endpoint may not be available") + if text: print(f" Response: {text[:200]}...") - - except aiohttp.ClientError as e: - print(f" โŒ Connection error: {e}") - except Exception as e: - print(f" โŒ Unexpected error: {e}") - - if success: - print(f" โœจ Endpoint {endpoint} is working!") - else: - print(f" โš ๏ธ Endpoint {endpoint} not accessible") + else: + print(f" โš ๏ธ Unexpected status: {status}") + if text: + print(f" Response: {text[:200]}...") + + except aiohttp.ClientError as e: + print(f" โŒ Connection error: {type(e).__name__}: {e}") + except Exception as e: + print(f" โŒ Unexpected error: {type(e).__name__}: {e}") print("\n" + "=" * 50) - print("\n๐Ÿ“ Recommendations:") - print("1. Check if Dolibarr Web Services API REST module is enabled") - print("2. Verify API key is correct and has proper permissions") - print("3. Ensure URL format: https://domain.com/api/index.php") - return True + if working_endpoints: + print("\nโœจ Working endpoints:") + for endpoint in working_endpoints: + print(f" - {endpoint}") + else: + print("\nโš ๏ธ No endpoints are working!") + + return len(working_endpoints) > 0 -async def test_swagger_discovery(): - """Try to discover API endpoints via Swagger/OpenAPI.""" +async def test_swagger_endpoint(): + """Test Swagger/Explorer endpoint specifically.""" - base_url = os.getenv("DOLIBARR_URL", "") + base_url = os.getenv("DOLIBARR_URL", "").rstrip('/') api_key = os.getenv("DOLIBARR_API_KEY", "") if not base_url or not api_key: return - print("\n๐Ÿ” Attempting Swagger/OpenAPI discovery:") + print("\n๐Ÿ” Testing Swagger/Explorer endpoints:") print("=" * 50) + # Swagger endpoints to test + swagger_endpoints = [ + "explorer", + "explorer/index.html", + f"explorer/swagger.json?DOLAPIKEY={api_key}", + ] + headers = { "DOLAPIKEY": api_key, + "Accept": "application/json, text/html, */*" + } + + async with aiohttp.ClientSession() as session: + for endpoint in swagger_endpoints: + url = f"{base_url}/{endpoint}" + + try: + print(f"\nTesting: {url}") + + async with session.get(url, headers=headers, timeout=10, ssl=False) as response: + status = response.status + content_type = response.headers.get('Content-Type', '') + + print(f" Status: {status}") + print(f" Content-Type: {content_type}") + + if status == 200: + print(f" โœ… Found!") + + # If it's the swagger.json, try to parse it + if 'swagger.json' in endpoint: + text = await response.text() + try: + swagger_data = json.loads(text) + if 'paths' in swagger_data: + print(f" Available API endpoints:") + for path in list(swagger_data['paths'].keys())[:10]: + print(f" - {path}") + if len(swagger_data['paths']) > 10: + print(f" ... and {len(swagger_data['paths']) - 10} more") + except: + print(f" Could not parse Swagger JSON") + else: + text = await response.text() + print(f" Response preview: {text[:100]}...") + + except Exception as e: + print(f" Error: {type(e).__name__}: {e}") + + +async def test_login_endpoint(): + """Test the login endpoint to get a session token.""" + + base_url = os.getenv("DOLIBARR_URL", "").rstrip('/') + api_key = os.getenv("DOLIBARR_API_KEY", "") + + if not base_url or not api_key: + return + + print("\n๐Ÿ” Testing Login endpoint:") + print("=" * 50) + + # Test with API key in header (standard method) + url = f"{base_url}/login" + + headers = { + "DOLAPIKEY": api_key, + "Content-Type": "application/json", "Accept": "application/json" } - # Possible Swagger/OpenAPI URLs - swagger_urls = [ - base_url.replace('/api/index.php', '/api/explorer'), - base_url.replace('/api/index.php', '/api/swagger.json'), - base_url.replace('/api/index.php', '/api/openapi.json'), - base_url.replace('/api/index.php', '/api/v2/swagger.json'), - ] - async with aiohttp.ClientSession() as session: - for url in swagger_urls: - try: - print(f"Testing: {url}") - async with session.get(url, headers=headers, timeout=5) as response: - if response.status == 200: - print(f"โœ… Found API documentation at: {url}") - break - except: - pass + try: + print(f"Testing: {url}") + print(f"Method: GET with DOLAPIKEY header") + + async with session.get(url, headers=headers, timeout=10, ssl=False) as response: + status = response.status + text = await response.text() + + print(f" Status: {status}") + + if status == 200: + print(f" โœ… Authentication successful!") + try: + data = json.loads(text) + print(f" Response: {json.dumps(data, indent=2)}") + except: + print(f" Response: {text}") + else: + print(f" Response: {text[:200]}...") + + except Exception as e: + print(f" Error: {type(e).__name__}: {e}") if __name__ == "__main__": @@ -167,8 +227,23 @@ if __name__ == "__main__": print("================================\n") try: - asyncio.run(test_dolibarr_connection()) - asyncio.run(test_swagger_discovery()) + # Run tests + success = asyncio.run(test_dolibarr_connection()) + asyncio.run(test_swagger_endpoint()) + asyncio.run(test_login_endpoint()) + + print("\n" + "=" * 50) + print("\n๐Ÿ“ Summary:") + if success: + print(" โœ… API connection is working!") + print(" You can proceed with MCP server implementation.") + else: + print(" โš ๏ธ API connection issues detected.") + print(" Please check:") + print(" 1. Dolibarr Web Services API REST module is enabled") + print(" 2. API key is correct and has proper permissions") + print(" 3. URL format is: https://domain.com/api/index.php/") + except KeyboardInterrupt: print("\n\n๐Ÿ‘‹ Test cancelled by user") sys.exit(0)