Files
Brancheneinstufung2/connector-superoffice/polling_daemon_sketch.py

148 lines
5.7 KiB
Python

import os
import sqlite3
import hashlib
import time
from datetime import datetime, timezone
from superoffice_client import SuperOfficeClient
# --- CONFIGURATION ---
DB_FILE_MATRIX = "marketing_matrix.db"
DB_FILE_STATE = "processing_state.db"
POLLING_INTERVAL_SECONDS = 300 # 5 minutes
# UDF ProgIds
PROG_ID_CONTACT_VERTICAL = "SuperOffice:5"
PROG_ID_PERSON_ROLE = "SuperOffice:3"
PROG_ID_CONTACT_CHALLENGE = "SuperOffice:6"
PROG_ID_PERSON_SUBJECT = "SuperOffice:5"
PROG_ID_PERSON_INTRO = "SuperOffice:6"
PROG_ID_PERSON_PROOF = "SuperOffice:7"
PROG_ID_PERSON_HASH = "SuperOffice:8"
# --- DATABASE SETUP ---
def init_state_db():
conn = sqlite3.connect(DB_FILE_STATE)
c = conn.cursor()
# Stores the last known hash for a person to detect changes
c.execute('''CREATE TABLE IF NOT EXISTS person_state
(person_id INTEGER PRIMARY KEY,
last_known_hash TEXT,
last_updated TEXT)''')
# Stores the timestamp of the last run
c.execute('''CREATE TABLE IF NOT EXISTS system_state
(key TEXT PRIMARY KEY, value TEXT)''')
c.execute("INSERT OR IGNORE INTO system_state VALUES ('last_run_utc', ?)", (datetime.utcnow().isoformat(),))
conn.commit()
conn.close()
print("✅ State DB initialized.")
# --- CORE LOGIC ---
def get_text_from_matrix(vertical_id, role_id):
# (Same as in webhook_server)
# ... (omitted for brevity, will be imported)
pass
def process_person(client: SuperOfficeClient, person_id: int):
# (Central logic from webhook_server, adapted slightly)
# ... (omitted for brevity, will be imported/reused)
pass
def poll_for_changes(client: SuperOfficeClient, last_run_utc: str):
print(f"Polling for persons modified since {last_run_utc}...")
# API Query: Get recently updated persons
# We select the fields we need to minimize payload
select_fields = "personId,contact/contactId,userDefinedFields"
filter_query = f"lastModified gt '{last_run_utc}'"
# In a real scenario, you'd handle paging for many results
recently_updated_persons = client.search(f"Person?$select={select_fields}&$filter={filter_query}")
if not recently_updated_persons:
print("No persons updated since last run.")
return
print(f"Found {len(recently_updated_persons)} updated persons to check.")
conn = sqlite3.connect(DB_FILE_STATE)
c = conn.cursor()
for person in recently_updated_persons:
person_id = person.get('personId')
try:
# 1. Get current state from SuperOffice
udfs = person.get('UserDefinedFields', {})
vertical_id_raw = client.get_contact(person['contact']['contactId'])["UserDefinedFields"].get(PROG_ID_CONTACT_VERTICAL, "")
role_id_raw = udfs.get(PROG_ID_PERSON_ROLE, "")
if not vertical_id_raw or not role_id_raw:
print(f" - Skipping Person {person_id}: Missing Vertical/Role ID.")
continue
vertical_id = int(vertical_id_raw.replace("[I:", "").replace("]", ""))
role_id = int(role_id_raw.replace("[I:", "").replace("]", ""))
# 2. Generate the "expected" hash
expected_hash = hashlib.md5(f"{vertical_id}-{role_id}".encode()).hexdigest()
# 3. Get last known hash from our state DB
c.execute("SELECT last_known_hash FROM person_state WHERE person_id = ?", (person_id,))
result = c.fetchone()
last_known_hash = result[0] if result else None
# 4. Compare and act
if expected_hash != last_known_hash:
print(f" -> Change detected for Person {person_id} (New state: V:{vertical_id}/R:{role_id}). Processing...")
# Here we would call the full processing logic from webhook_server.py
# For now, we simulate the update and save the new state.
# process_single_person(client, person_id) # This would be the real call
# Update our state DB
c.execute("INSERT OR REPLACE INTO person_state VALUES (?, ?, ?)",
(person_id, expected_hash, datetime.utcnow().isoformat()))
conn.commit()
print(f" ✅ Processed and updated state for Person {person_id}.")
else:
print(f" - Skipping Person {person_id}: No relevant change detected (hash is the same).")
except Exception as e:
print(f" - ❌ Error processing Person {person_id}: {e}")
conn.close()
# --- MAIN DAEMON LOOP ---
def main():
init_state_db()
try:
client = SuperOfficeClient()
except Exception as e:
print(f"Could not start daemon: {e}")
return
while True:
conn = sqlite3.connect(DB_FILE_STATE)
c = conn.cursor()
c.execute("SELECT value FROM system_state WHERE key = 'last_run_utc'")
last_run = c.fetchone()[0]
# Poll for changes
poll_for_changes(client, last_run)
# Update last run time
new_last_run = datetime.utcnow().isoformat()
c.execute("UPDATE system_state SET value = ? WHERE key = 'last_run_utc'", (new_last_run,))
conn.commit()
conn.close()
print(f"\nPolling complete. Next run in {POLLING_INTERVAL_SECONDS} seconds...")
time.sleep(POLLING_INTERVAL_SECONDS)
if __name__ == '__main__':
# This is a conceptual sketch.
# The SuperOfficeClient needs a `search` method.
# The logic from webhook_server needs to be callable.
print("This script is a blueprint for the polling daemon.")
print("It requires a `search` method in the SuperOfficeClient and refactoring.")