#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Fetches messages from Medevio API. Modes: - Incremental (default): Only requests where messagesProcessed IS NULL or < updatedAt - Full resync (--full): Fetches ALL messages for ALL pozadavky """ import zlib import json import requests import pymysql from pathlib import Path from datetime import datetime import time import argparse # ============================== # 🔧 CONFIGURATION # ============================== TOKEN_PATH = Path("token.txt") DB_CONFIG = { "host": "192.168.1.76", "port": 3307, "user": "root", "password": "Vlado9674+", "database": "medevio", "charset": "utf8mb4", "cursorclass": pymysql.cursors.DictCursor, } GRAPHQL_QUERY_MESSAGES = r""" query UseMessages_ListMessages($requestId: String!, $updatedSince: DateTime) { messages: listMessages(patientRequestId: $requestId, updatedSince: $updatedSince) { id createdAt updatedAt readAt text type sender { id name surname clinicId } medicalRecord { id description contentType url downloadUrl token createdAt updatedAt } } } """ # ============================== # ⏱ DATETIME PARSER # ============================== def parse_dt(s): if not s: return None try: return datetime.fromisoformat(s.replace("Z", "+00:00")) except: pass try: return datetime.strptime(s[:19], "%Y-%m-%dT%H:%M:%S") except: return None # ============================== # 🔐 TOKEN # ============================== def read_token(path: Path) -> str: tok = path.read_text(encoding="utf-8").strip() return tok.replace("Bearer ", "") # ============================== # 📡 FETCH MESSAGES # ============================== def fetch_messages(headers, request_id): payload = { "operationName": "UseMessages_ListMessages", "query": GRAPHQL_QUERY_MESSAGES, "variables": {"requestId": request_id, "updatedSince": None}, } r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30) if r.status_code != 200: print("❌ HTTP", r.status_code, "for request", request_id) return [] return r.json().get("data", {}).get("messages", []) or [] # ============================== # 💾 SAVE MESSAGE # ============================== def insert_message(cur, req_id, msg): sender = msg.get("sender") or {} sender_name = " ".join( x for x in [sender.get("name"), sender.get("surname")] if x ) or None sql = """ INSERT INTO medevio_conversation ( id, request_id, sender_name, sender_id, sender_clinic_id, text, created_at, read_at, updated_at, attachment_url, attachment_description, attachment_content_type ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ON DUPLICATE KEY UPDATE sender_name = VALUES(sender_name), sender_id = VALUES(sender_id), sender_clinic_id = VALUES(sender_clinic_id), text = VALUES(text), created_at = VALUES(created_at), read_at = VALUES(read_at), updated_at = VALUES(updated_at), attachment_url = VALUES(attachment_url), attachment_description = VALUES(attachment_description), attachment_content_type = VALUES(attachment_content_type) """ mr = msg.get("medicalRecord") or {} cur.execute(sql, ( msg.get("id"), req_id, sender_name, sender.get("id"), sender.get("clinicId"), msg.get("text"), parse_dt(msg.get("createdAt")), parse_dt(msg.get("readAt")), parse_dt(msg.get("updatedAt")), mr.get("downloadUrl") or mr.get("url"), mr.get("description"), mr.get("contentType") )) # ============================== # 💾 DOWNLOAD MESSAGE ATTACHMENT # ============================== def insert_download(cur, req_id, msg, existing_ids): mr = msg.get("medicalRecord") or {} attachment_id = mr.get("id") if not attachment_id: return if attachment_id in existing_ids: return # skip duplicates url = mr.get("downloadUrl") or mr.get("url") if not url: return try: r = requests.get(url, timeout=30) r.raise_for_status() data = r.content except Exception as e: print("⚠️ Failed to download:", e) return filename = url.split("/")[-1].split("?")[0] cur.execute(""" INSERT INTO medevio_downloads ( request_id, attachment_id, attachment_type, filename, content_type, file_size, created_at, file_content ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s) ON DUPLICATE KEY UPDATE file_content = VALUES(file_content), file_size = VALUES(file_size), downloaded_at = NOW() """, ( req_id, attachment_id, "MESSAGE_ATTACHMENT", filename, mr.get("contentType"), len(data), parse_dt(msg.get("createdAt")), data )) existing_ids.add(attachment_id) # ============================== # 🧠 MAIN # ============================== def main(): parser = argparse.ArgumentParser() parser.add_argument("--full", action="store_true", help="Load messages for ALL pozadavky") # Force full mode ON args = parser.parse_args(args=["--full"]) # args = parser.parse_args() token = read_token(TOKEN_PATH) headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", "Accept": "application/json", } conn = pymysql.connect(**DB_CONFIG) # ---- Load existing attachments with conn.cursor() as cur: cur.execute("SELECT attachment_id FROM medevio_downloads") existing_ids = {row["attachment_id"] for row in cur.fetchall()} print(f"📦 Already downloaded attachments: {len(existing_ids)}\n") # ---- Select pozadavky to process with conn.cursor() as cur: if args.full: print("🔁 FULL REFRESH MODE: Fetching messages for ALL pozadavky!\n") cur.execute("SELECT id FROM pozadavky") else: print("📥 Incremental mode: Only syncing updated pozadavky.\n") cur.execute(""" SELECT id FROM pozadavky WHERE messagesProcessed IS NULL OR messagesProcessed < updatedAt """) requests_to_process = cur.fetchall() # ================================= # ⏩ SKIP FIRST 3100 AS YESTERDAY # ================================= SKIP = 3100 if len(requests_to_process) > SKIP: print(f"⏩ Skipping first {SKIP} pozadavky (already processed yesterday).") requests_to_process = requests_to_process[SKIP:] else: print("⚠️ Not enough pozadavky to skip!") print(f"📋 Requests to process: {len(requests_to_process)}\n") # ---- Process each request for idx, row in enumerate(requests_to_process, 1): req_id = row["id"] print(f"[{idx}/{len(requests_to_process)}] Processing {req_id} …") messages = fetch_messages(headers, req_id) with conn.cursor() as cur: for msg in messages: insert_message(cur, req_id, msg) insert_download(cur, req_id, msg, existing_ids) conn.commit() with conn.cursor() as cur: cur.execute("UPDATE pozadavky SET messagesProcessed = NOW() WHERE id = %s", (req_id,)) conn.commit() print(f" ✅ {len(messages)} messages saved\n") time.sleep(0.25) conn.close() print("🎉 Done!") if __name__ == "__main__": main()