feat: Build complete POC for Butler model (client, matrix, daemon)

This commit is contained in:
Jarvis
2026-02-12 14:18:52 +00:00
parent d934165908
commit e455519a12
13 changed files with 1288 additions and 352 deletions

View File

@@ -1,49 +1,89 @@
# connector-superoffice/discover_fields.py (Standalone & Robust)
import os
from config import Config
from logging_config import setup_logging
from auth_handler import AuthHandler
from superoffice_client import SuperOfficeClient
import requests
import json
from dotenv import load_dotenv
logger = setup_logging("discovery")
# Load environment variables
load_dotenv(override=True)
def get_list_items_by_prog_id(client, prog_id, entity_name):
"""Fetches and prints list items for a specific ProgId."""
logger.info(f"--- Fetching list items for {entity_name} ProgId: {prog_id} ---")
list_url = client._get_url(f"v1/List/UserDefinedField/{prog_id}")
# Configuration
SO_ENV = os.getenv("SO_ENVIRONMENT", "sod") # sod, stage, online
SO_CLIENT_ID = os.getenv("SO_CLIENT_ID") or os.getenv("SO_SOD")
SO_CLIENT_SECRET = os.getenv("SO_CLIENT_SECRET")
# SO_REDIRECT_URI often required for validation even in refresh flow
SO_REDIRECT_URI = os.getenv("SO_REDIRECT_URI", "http://localhost")
SO_REFRESH_TOKEN = os.getenv("SO_REFRESH_TOKEN")
def get_access_token():
"""Refreshes the access token using the refresh token."""
url = f"https://{SO_ENV}.superoffice.com/login/common/oauth/tokens"
data = {
"grant_type": "refresh_token",
"client_id": SO_CLIENT_ID,
"client_secret": SO_CLIENT_SECRET,
"refresh_token": SO_REFRESH_TOKEN,
"redirect_uri": SO_REDIRECT_URI
}
print(f"DEBUG: Refreshing token at {url} for Client ID {SO_CLIENT_ID[:5]}...")
response = requests.post(url, data=data)
if response.status_code == 200:
print("✅ Access Token refreshed.")
return response.json().get("access_token")
else:
print(f"❌ Error getting token: {response.text}")
return None
def discover_udfs(base_url, token, entity="Contact"):
"""
Fetches the UDF layout for a specific entity.
entity: 'Contact' (Firma) or 'Person'
"""
endpoint = "Contact" if entity == "Contact" else "Person"
url = f"{base_url}/api/v1/{endpoint}?$top=1&$select=userDefinedFields"
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json"
}
print(f"\n--- DISCOVERING UDFS FOR: {entity} ---")
try:
list_resp = client.session.get(list_url, headers=client._get_headers())
list_resp.raise_for_status()
list_items = list_resp.json()
if list_items.get("value"):
print(f" --- List Items Found for {prog_id} ---")
for item in list_items["value"]:
print(f" ID: {item.get('Id'):<5} | Name: {item.get('Name')}")
return {item.get('Name'): item.get('Id') for item in list_items["value"]}
response = requests.get(url, headers=headers)
if response.status_code == 200:
data = response.json()
if data['value']:
item = data['value'][0]
udfs = item.get('userDefinedFields', {})
print(f"Found {len(udfs)} UDFs on this record.")
# Filter logic: Show interesting fields
relevant_udfs = {k: v for k, v in udfs.items() if "marketing" in k.lower() or "robotic" in k.lower() or "challenge" in k.lower() or "ai" in k.lower()}
if relevant_udfs:
print("✅ FOUND RELEVANT FIELDS (ProgId : Value):")
print(json.dumps(relevant_udfs, indent=2))
else:
print("⚠️ No fields matching 'marketing/robotic/ai' found.")
print("First 5 UDFs for context:")
print(json.dumps(list(udfs.keys())[:5], indent=2))
else:
print("No records found to inspect.")
else:
print(f"Error {response.status_code}: {response.text}")
except Exception as e:
logger.error(f"Failed to fetch list items for {prog_id}: {e}")
return None
def get_activity_types(client):
"""Fetches available activity types."""
logger.info("--- Fetching Activity Types ---")
url = client._get_url("v1/ActivityType")
try:
resp = client.session.get(url, headers=client._get_headers())
resp.raise_for_status()
activity_types = resp.json()
if activity_types:
print(" --- Activity Types Found ---")
for atype in activity_types:
print(f" ID: {atype.get('Id'):<5} | Name: {atype.get('Name')}")
return {atype.get('Name'): atype.get('Id') for atype in activity_types}
except Exception as e:
logger.error(f"Failed to fetch activity types: {e}")
return None
def main():
auth = AuthHandler()
client = SuperOfficeClient(auth)
get_activity_types(client)
print(f"Request failed: {e}")
if __name__ == "__main__":
main()
token = get_access_token()
if token:
# Hardcoded Base URL for Cust55774 (Fix: Use app-sod as per README)
base_url = "https://app-sod.superoffice.com/Cust55774"
discover_udfs(base_url, token, "Person")
discover_udfs(base_url, token, "Contact")
else:
print("Could not get Access Token. Check .env")