diff --git a/.idea/Medevio.iml b/.idea/Medevio.iml
index 6cb8b9a..78fd998 100644
--- a/.idea/Medevio.iml
+++ b/.idea/Medevio.iml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 3c48b1e..7b70d2f 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/10ReadPozadavky/0704 Plne funkční uložení do mysql.py b/10ReadPozadavky/0704 Plne funkční uložení do mysql.py
index e69de29..f90c67d 100644
--- a/10ReadPozadavky/0704 Plne funkční uložení do mysql.py
+++ b/10ReadPozadavky/0704 Plne funkční uložení do mysql.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+Download all 'Odeslat lékařskou zprávu' attachments from Medevio API
+and store them (including binary content) directly into MySQL table `medevio_downloads`.
+
+Each attachment (PDF, image, etc.) is fetched once and saved as LONGBLOB.
+Duplicate protection is ensured via UNIQUE KEY on `attachment_id`.
+"""
+
+import zlib
+import json
+import requests
+import pymysql
+from pathlib import Path
+from datetime import datetime
+import time
+
+# ==============================
+# 🔧 CONFIGURATION
+# ==============================
+TOKEN_PATH = Path("token.txt")
+CLINIC_SLUG = "mudr-buzalkova"
+
+DB_CONFIG = {
+ "host": "192.168.1.76",
+ "port": 3307,
+ "user": "root",
+ "password": "Vlado9674+",
+ "database": "medevio",
+ "charset": "utf8mb4",
+ "cursorclass": pymysql.cursors.DictCursor,
+}
+
+GRAPHQL_QUERY = r"""
+query ClinicRequestDetail_GetPatientRequest2($requestId: UUID!) {
+ patientRequestMedicalRecords: listMedicalRecordsForPatientRequest(
+ attachmentTypes: [ECRF_FILL_ATTACHMENT, MESSAGE_ATTACHMENT, PATIENT_REQUEST_ATTACHMENT]
+ patientRequestId: $requestId
+ pageInfo: {first: 100, offset: 0}
+ ) {
+ attachmentType
+ id
+ medicalRecord {
+ contentType
+ description
+ downloadUrl
+ id
+ url
+ visibleToPatient
+ }
+ }
+}
+"""
+
+# ==============================
+# 🧮 HELPERS
+# ==============================
+def short_crc8(uuid_str: str) -> str:
+ """Return deterministic 8-char hex string from any input string (CRC32)."""
+ return f"{zlib.crc32(uuid_str.encode('utf-8')) & 0xffffffff:08x}"
+
+def extract_filename_from_url(url: str) -> str:
+ """Extracts filename from S3-style URL (between last '/' and first '?')."""
+ try:
+ return url.split("/")[-1].split("?")[0]
+ except Exception:
+ return "unknown_filename"
+
+def read_token(p: Path) -> str:
+ """Read Bearer token from file."""
+ tok = p.read_text(encoding="utf-8").strip()
+ if tok.startswith("Bearer "):
+ tok = tok.split(" ", 1)[1]
+ return tok
+
+# ==============================
+# 📡 FETCH ATTACHMENTS
+# ==============================
+def fetch_attachments(headers, request_id):
+ variables = {"requestId": request_id}
+ payload = {
+ "operationName": "ClinicRequestDetail_GetPatientRequest2",
+ "query": GRAPHQL_QUERY,
+ "variables": variables,
+ }
+ r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
+ if r.status_code != 200:
+ print(f"❌ HTTP {r.status_code} for request {request_id}")
+ return []
+ data = r.json().get("data", {}).get("patientRequestMedicalRecords", [])
+ return data
+
+# ==============================
+# 💾 SAVE TO MYSQL (with skip)
+# ==============================
+def insert_download(cur, req_id, a, m, jmeno, prijmeni, created_date, existing_ids):
+ attachment_id = a.get("id")
+ if attachment_id in existing_ids:
+ print(f" ⏭️ Skipping already downloaded attachment {attachment_id}")
+ return
+
+ url = m.get("downloadUrl")
+ if not url:
+ print(" ⚠️ No download URL")
+ return
+
+ filename = extract_filename_from_url(url)
+ try:
+ r = requests.get(url, timeout=30)
+ r.raise_for_status()
+ content = r.content
+ except Exception as e:
+ print(f" ⚠️ Failed to download {url}: {e}")
+ return
+
+ file_size = len(content)
+ attachment_type = a.get("attachmentType")
+ content_type = m.get("contentType")
+
+ cur.execute("""
+ INSERT INTO medevio_downloads (
+ request_id, attachment_id, attachment_type, filename,
+ content_type, file_size, pacient_jmeno, pacient_prijmeni,
+ created_at, file_content
+ ) VALUES (%s,%s,%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,
+ attachment_type,
+ filename,
+ content_type,
+ file_size,
+ jmeno,
+ prijmeni,
+ created_date,
+ content
+ ))
+ print(f" 💾 Saved {filename} ({file_size/1024:.1f} kB)")
+ existing_ids.add(attachment_id) # add to skip list
+
+# ==============================
+# 🧠 MAIN
+# ==============================
+def main():
+ token = read_token(TOKEN_PATH)
+ headers = {
+ "Authorization": f"Bearer {token}",
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ }
+
+ conn = pymysql.connect(**DB_CONFIG)
+
+ print("📦 Loading list of already downloaded 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"✅ Found {len(existing_ids)} attachments already saved.")
+
+
+ with conn.cursor() as cur:
+ cur.execute("""
+ SELECT id, displayTitle, pacient_prijmeni, pacient_jmeno, createdAt
+ FROM pozadavky
+ WHERE displayTitle = 'Odeslat lékařskou zprávu'
+ """)
+ rows = cur.fetchall()
+
+ print(f"📋 Found {len(rows)} 'Odeslat lékařskou zprávu' requests")
+
+ for i, row in enumerate(rows, 1):
+ req_id = row["id"]
+ prijmeni = row.get("pacient_prijmeni") or "Neznamy"
+ jmeno = row.get("pacient_jmeno") or ""
+ created = row.get("createdAt")
+
+ try:
+ created_date = datetime.strptime(str(created), "%Y-%m-%d %H:%M:%S")
+ except Exception:
+ created_date = None
+
+ print(f"\n[{i}/{len(rows)}] 🧾 {prijmeni}, {jmeno} ({req_id})")
+
+ attachments = fetch_attachments(headers, req_id)
+ if not attachments:
+ print(" ⚠️ No attachments")
+ continue
+
+ with conn.cursor() as cur:
+ for a in attachments:
+ m = a.get("medicalRecord") or {}
+ insert_download(cur, req_id, a, m, jmeno, prijmeni, created_date, existing_ids)
+ conn.commit()
+
+ print(f" ✅ {len(attachments)} attachments saved for {prijmeni}, {jmeno}")
+ time.sleep(0.5) # be nice to the API
+
+ conn.close()
+ print("\n✅ Done! All attachments stored in MySQL table `medevio_downloads`.")
+
+# ==============================
+if __name__ == "__main__":
+ main()
diff --git a/10ReadPozadavky/08 Read communication.py b/10ReadPozadavky/08 Read communication.py
new file mode 100644
index 0000000..dd51d83
--- /dev/null
+++ b/10ReadPozadavky/08 Read communication.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+Fetch communication threads (messages) from Medevio API
+for pozadavky where communicationprocessed IS NULL or outdated,
+optionally filtered by creation date.
+Stores results in MySQL table `medevio_messages`.
+"""
+
+import requests
+import pymysql
+from pathlib import Path
+from datetime import datetime
+import time
+
+# ==============================
+# 🔧 CONFIGURATION
+# ==============================
+TOKEN_PATH = Path("token.txt")
+GRAPHQL_URL = "https://api.medevio.cz/graphql"
+
+DB_CONFIG = {
+ "host": "192.168.1.76",
+ "port": 3307,
+ "user": "root",
+ "password": "Vlado9674+",
+ "database": "medevio",
+ "charset": "utf8mb4",
+ "cursorclass": pymysql.cursors.DictCursor,
+}
+
+# ✅ Optional: Only process requests created after this date
+# Leave empty ("") to process all
+CREATED_AFTER = "2025-11-09" # 🕓 Adjust freely, or set to "" for no limit
+
+# ==============================
+# 🔐 TOKEN
+# ==============================
+def read_token(p: Path) -> str:
+ tok = p.read_text(encoding="utf-8").strip()
+ return tok.split(" ", 1)[1] if tok.startswith("Bearer ") else tok
+
+
+headers = {
+ "Authorization": f"Bearer {read_token(TOKEN_PATH)}",
+ "Content-Type": "application/json",
+}
+
+# ==============================
+# 🧩 GRAPHQL QUERY
+# ==============================
+GRAPHQL_QUERY = """
+query UseMessages_ListMessages($requestId: String!, $updatedSince: DateTime) {
+ messages: listMessages(
+ patientRequestId: $requestId
+ updatedSince: $updatedSince
+ ) {
+ id
+ createdAt
+ text
+ updatedAt
+ readAt
+ sender { id name surname clinicId }
+ medicalRecord { downloadUrl description contentType }
+ }
+}
+"""
+
+# ==============================
+# 🧮 HELPERS
+# ==============================
+def normalize_ts(ts: str):
+ """Convert ISO 8601 string to MySQL DATETIME format."""
+ if not ts:
+ return None
+ ts = ts.replace("T", " ").replace("Z", "")
+ if "." in ts:
+ ts = ts.split(".")[0]
+ return ts
+
+
+# ==============================
+# 📡 FETCH MESSAGES
+# ==============================
+def fetch_messages(request_id):
+ payload = {
+ "operationName": "UseMessages_ListMessages",
+ "variables": {"requestId": request_id, "updatedSince": None},
+ "query": GRAPHQL_QUERY,
+ }
+ r = requests.post(GRAPHQL_URL, headers=headers, json=payload, timeout=30)
+ if r.status_code != 200:
+ print(f"❌ HTTP {r.status_code}: {r.text}")
+ return []
+ return r.json().get("data", {}).get("messages", []) or []
+
+
+# ==============================
+# 💾 CREATE TABLE IF NEEDED
+# ==============================
+def ensure_table_exists(conn):
+ with conn.cursor() as cur:
+ cur.execute("""
+ CREATE TABLE IF NOT EXISTS medevio_messages (
+ id VARCHAR(64) PRIMARY KEY,
+ request_id VARCHAR(64),
+ sender_name VARCHAR(255),
+ sender_id VARCHAR(64),
+ sender_clinic_id VARCHAR(64),
+ text TEXT,
+ created_at DATETIME NULL,
+ read_at DATETIME NULL,
+ updated_at DATETIME NULL,
+ attachment_url TEXT,
+ attachment_description TEXT,
+ attachment_content_type VARCHAR(128),
+ inserted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+ """)
+ conn.commit()
+
+
+# ==============================
+# 💾 INSERT MESSAGE
+# ==============================
+def insert_message(cur, req_id, msg):
+ sender = msg.get("sender") or {}
+ medrec = msg.get("medicalRecord") or {}
+
+ cur.execute("""
+ REPLACE INTO medevio_messages (
+ 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)
+ """, (
+ msg.get("id"),
+ req_id,
+ f"{sender.get('name','')} {sender.get('surname','')}".strip(),
+ sender.get("id"),
+ sender.get("clinicId"),
+ msg.get("text"),
+ normalize_ts(msg.get("createdAt")),
+ normalize_ts(msg.get("readAt")),
+ normalize_ts(msg.get("updatedAt")),
+ medrec.get("downloadUrl"),
+ medrec.get("description"),
+ medrec.get("contentType")
+ ))
+
+
+# ==============================
+# 🧠 MAIN
+# ==============================
+def main():
+ conn = pymysql.connect(**DB_CONFIG)
+ ensure_table_exists(conn)
+
+ with conn.cursor() as cur:
+ sql = """
+ SELECT id, createdAt, updatedAt, communicationprocessed
+ FROM pozadavky
+ WHERE (communicationprocessed IS NULL OR communicationprocessed < updatedAt)
+ """
+ if CREATED_AFTER:
+ sql += " AND createdAt >= %s"
+ cur.execute(sql, (CREATED_AFTER,))
+ else:
+ cur.execute(sql)
+
+ rows = cur.fetchall()
+
+ if not rows:
+ print("✅ No pending communication updates.")
+ return
+
+ print(f"📋 Found {len(rows)} requests needing communication check.")
+
+ for i, row in enumerate(rows, 1):
+ req_id = row["id"]
+ print(f"\n[{i}/{len(rows)}] 🔍 Fetching communication for {req_id} ...")
+
+ messages = fetch_messages(req_id)
+ print(f" 💬 {len(messages)} messages found.")
+
+ # Update timestamp even if none found
+ with conn.cursor() as cur:
+ if messages:
+ for msg in messages:
+ insert_message(cur, req_id, msg)
+ cur.execute("""
+ UPDATE pozadavky
+ SET communicationprocessed = NOW()
+ WHERE id = %s
+ """, (req_id,))
+ conn.commit()
+
+ print(f" ✅ Processed {len(messages)} messages for {req_id}")
+ time.sleep(0.5) # avoid hammering the API
+
+ conn.close()
+ print("\n✅ All communication threads processed and timestamps updated.")
+
+
+# ==============================
+if __name__ == "__main__":
+ main()
diff --git a/10ReadPozadavky/09 Read dotaznik.py b/10ReadPozadavky/09 Read dotaznik.py
new file mode 100644
index 0000000..6eea770
--- /dev/null
+++ b/10ReadPozadavky/09 Read dotaznik.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+Download and store Medevio questionnaires (userNote + eCRF) for all patient requests.
+Uses the verified working query "GetPatientRequest2".
+"""
+
+import json
+import requests
+import pymysql
+from datetime import datetime
+from pathlib import Path
+import time
+
+# ==============================
+# 🔧 CONFIGURATION
+# ==============================
+TOKEN_PATH = Path("token.txt")
+CLINIC_SLUG = "mudr-buzalkova"
+GRAPHQL_URL = "https://api.medevio.cz/graphql"
+
+DB_CONFIG = {
+ "host": "192.168.1.76",
+ "port": 3307,
+ "user": "root",
+ "password": "Vlado9674+",
+ "database": "medevio",
+ "charset": "utf8mb4",
+ "cursorclass": pymysql.cursors.DictCursor,
+}
+
+
+from datetime import datetime
+
+def fix_datetime(dt_str):
+ """Convert ISO 8601 string with 'Z' or ms into MySQL DATETIME format."""
+ if not dt_str:
+ return None
+ try:
+ # Remove trailing Z and parse flexible ISO format
+ return datetime.fromisoformat(dt_str.replace("Z", "").replace("+00:00", ""))
+ except Exception:
+ return None
+
+# ✅ Optional: limit which requests to process
+CREATED_AFTER = "2025-11-09" # set "" to disable
+
+# ==============================
+# 🧮 HELPERS
+# ==============================
+def read_token(p: Path) -> str:
+ """Read Bearer token from file."""
+ tok = p.read_text(encoding="utf-8").strip()
+ if tok.startswith("Bearer "):
+ tok = tok.split(" ", 1)[1]
+ return tok
+
+
+GRAPHQL_QUERY = r"""
+query GetPatientRequest2($requestId: UUID!, $clinicSlug: String!, $locale: Locale!) {
+ request: getPatientRequest2(patientRequestId: $requestId, clinicSlug: $clinicSlug) {
+ id
+ displayTitle(locale: $locale)
+ createdAt
+ updatedAt
+ userNote
+ eventType
+ extendedPatient(clinicSlug: $clinicSlug) {
+ name
+ surname
+ identificationNumber
+ }
+ ecrfFilledData(locale: $locale) {
+ name
+ groups {
+ label
+ fields {
+ name
+ label
+ type
+ value
+ }
+ }
+ }
+ }
+}
+"""
+
+
+def fetch_questionnaire(headers, request_id, clinic_slug):
+ """Fetch questionnaire for given request ID."""
+ payload = {
+ "operationName": "GetPatientRequest2",
+ "query": GRAPHQL_QUERY,
+ "variables": {
+ "requestId": request_id,
+ "clinicSlug": clinic_slug,
+ "locale": "cs",
+ },
+ }
+ r = requests.post(GRAPHQL_URL, json=payload, headers=headers, timeout=40)
+ if r.status_code != 200:
+ print(f"❌ HTTP {r.status_code} for {request_id}: {r.text}")
+ return None
+ return r.json().get("data", {}).get("request")
+
+
+def insert_questionnaire(cur, req):
+ """Insert questionnaire data into MySQL."""
+ if not req:
+ return
+
+ patient = req.get("extendedPatient") or {}
+ ecrf_data = req.get("ecrfFilledData")
+
+ created_at = fix_datetime(req.get("createdAt"))
+ updated_at = fix_datetime(req.get("updatedAt"))
+
+ cur.execute("""
+ INSERT INTO medevio_questionnaires (
+ request_id, patient_name, patient_surname, patient_identification,
+ created_at, updated_at, user_note, ecrf_json
+ )
+ VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
+ ON DUPLICATE KEY UPDATE
+ updated_at = VALUES(updated_at),
+ user_note = VALUES(user_note),
+ ecrf_json = VALUES(ecrf_json),
+ updated_local = NOW()
+ """, (
+ req.get("id"),
+ patient.get("name"),
+ patient.get("surname"),
+ patient.get("identificationNumber"),
+ created_at,
+ updated_at,
+ req.get("userNote"),
+ json.dumps(ecrf_data, ensure_ascii=False),
+ ))
+ print(f" 💾 Stored questionnaire for {patient.get('surname','')} {patient.get('name','')}")
+
+
+# ==============================
+# 🧠 MAIN
+# ==============================
+def main():
+ token = read_token(TOKEN_PATH)
+ headers = {
+ "Authorization": f"Bearer {token}",
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ }
+
+ conn = pymysql.connect(**DB_CONFIG)
+ with conn.cursor() as cur:
+ sql = """
+ SELECT id, pacient_jmeno, pacient_prijmeni, createdAt, updatedAt, questionnaireprocessed
+ FROM pozadavky
+ WHERE (questionnaireprocessed IS NULL OR questionnaireprocessed < updatedAt)
+ """
+ if CREATED_AFTER:
+ sql += " AND createdAt >= %s"
+ cur.execute(sql, (CREATED_AFTER,))
+ else:
+ cur.execute(sql)
+
+ rows = cur.fetchall()
+
+ print(f"📋 Found {len(rows)} requests needing questionnaire check.")
+
+ for i, row in enumerate(rows, 1):
+ req_id = row["id"]
+ print(f"\n[{i}/{len(rows)}] 🔍 Fetching questionnaire for {req_id} ...")
+
+ req = fetch_questionnaire(headers, req_id, CLINIC_SLUG)
+ if not req:
+ print(" ⚠️ No questionnaire data found.")
+ continue
+
+ with conn.cursor() as cur:
+ insert_questionnaire(cur, req)
+ cur.execute("UPDATE pozadavky SET questionnaireprocessed = NOW() WHERE id = %s", (req_id,))
+ conn.commit()
+
+ time.sleep(0.4) # polite pacing
+
+ conn.close()
+ print("\n✅ Done! All questionnaires stored in MySQL table `medevio_questionnaires`.")
+
+
+# ==============================
+if __name__ == "__main__":
+ main()
diff --git a/10ReadPozadavky/705 Plně funkční uložení do mysql.py b/10ReadPozadavky/705 Plně funkční uložení do mysql.py
new file mode 100644
index 0000000..eb9b074
--- /dev/null
+++ b/10ReadPozadavky/705 Plně funkční uložení do mysql.py
@@ -0,0 +1,228 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+"""
+Download all attachments for pozadavky where attachmentsProcessed IS NULL
+and (optionally) createdAt is newer than a configurable cutoff date.
+Store them in MySQL table `medevio_downloads`, and update pozadavky.attachmentsProcessed = NOW().
+"""
+
+import zlib
+import json
+import requests
+import pymysql
+from pathlib import Path
+from datetime import datetime
+import time
+
+# ==============================
+# 🔧 CONFIGURATION
+# ==============================
+TOKEN_PATH = Path("token.txt")
+CLINIC_SLUG = "mudr-buzalkova"
+
+DB_CONFIG = {
+ "host": "192.168.1.76",
+ "port": 3307,
+ "user": "root",
+ "password": "Vlado9674+",
+ "database": "medevio",
+ "charset": "utf8mb4",
+ "cursorclass": pymysql.cursors.DictCursor,
+}
+
+# ✅ Optional: Only process requests created after this date
+# Leave empty ("") to process all
+CREATED_AFTER = "2025-01-01" # 🕓 Adjust freely, or set to "" for no limit
+
+GRAPHQL_QUERY = r"""
+query ClinicRequestDetail_GetPatientRequest2($requestId: UUID!) {
+ patientRequestMedicalRecords: listMedicalRecordsForPatientRequest(
+ attachmentTypes: [ECRF_FILL_ATTACHMENT, MESSAGE_ATTACHMENT, PATIENT_REQUEST_ATTACHMENT]
+ patientRequestId: $requestId
+ pageInfo: {first: 100, offset: 0}
+ ) {
+ attachmentType
+ id
+ medicalRecord {
+ contentType
+ description
+ downloadUrl
+ id
+ url
+ visibleToPatient
+ }
+ }
+}
+"""
+
+# ==============================
+# 🧮 HELPERS
+# ==============================
+def short_crc8(uuid_str: str) -> str:
+ """Return deterministic 8-char hex string from any input string (CRC32)."""
+ return f"{zlib.crc32(uuid_str.encode('utf-8')) & 0xffffffff:08x}"
+
+def extract_filename_from_url(url: str) -> str:
+ """Extracts filename from S3-style URL (between last '/' and first '?')."""
+ try:
+ return url.split("/")[-1].split("?")[0]
+ except Exception:
+ return "unknown_filename"
+
+def read_token(p: Path) -> str:
+ """Read Bearer token from file."""
+ tok = p.read_text(encoding="utf-8").strip()
+ if tok.startswith("Bearer "):
+ tok = tok.split(" ", 1)[1]
+ return tok
+
+# ==============================
+# 📡 FETCH ATTACHMENTS
+# ==============================
+def fetch_attachments(headers, request_id):
+ variables = {"requestId": request_id}
+ payload = {
+ "operationName": "ClinicRequestDetail_GetPatientRequest2",
+ "query": GRAPHQL_QUERY,
+ "variables": variables,
+ }
+ r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
+ if r.status_code != 200:
+ print(f"❌ HTTP {r.status_code} for request {request_id}")
+ return []
+ data = r.json().get("data", {}).get("patientRequestMedicalRecords", [])
+ return data
+
+# ==============================
+# 💾 SAVE TO MYSQL (with skip)
+# ==============================
+def insert_download(cur, req_id, a, m, jmeno, prijmeni, created_date, existing_ids):
+ attachment_id = a.get("id")
+ if attachment_id in existing_ids:
+ print(f" ⏭️ Skipping already downloaded attachment {attachment_id}")
+ return False
+
+ url = m.get("downloadUrl")
+ if not url:
+ print(" ⚠️ No download URL")
+ return False
+
+ filename = extract_filename_from_url(url)
+ try:
+ r = requests.get(url, timeout=30)
+ r.raise_for_status()
+ content = r.content
+ except Exception as e:
+ print(f" ⚠️ Failed to download {url}: {e}")
+ return False
+
+ file_size = len(content)
+ attachment_type = a.get("attachmentType")
+ content_type = m.get("contentType")
+
+ cur.execute("""
+ INSERT INTO medevio_downloads (
+ request_id, attachment_id, attachment_type, filename,
+ content_type, file_size, pacient_jmeno, pacient_prijmeni,
+ created_at, file_content
+ ) VALUES (%s,%s,%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,
+ attachment_type,
+ filename,
+ content_type,
+ file_size,
+ jmeno,
+ prijmeni,
+ created_date,
+ content
+ ))
+ existing_ids.add(attachment_id)
+ print(f" 💾 Saved {filename} ({file_size/1024:.1f} kB)")
+ return True
+
+# ==============================
+# 🧠 MAIN
+# ==============================
+def main():
+ token = read_token(TOKEN_PATH)
+ headers = {
+ "Authorization": f"Bearer {token}",
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ }
+
+ conn = pymysql.connect(**DB_CONFIG)
+
+ print("📦 Loading list of already downloaded 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"✅ Found {len(existing_ids)} attachments already saved.")
+
+ # ✅ Dynamic SQL with optional createdAt filter
+ sql = """
+ SELECT id, displayTitle, pacient_prijmeni, pacient_jmeno, createdAt
+ FROM pozadavky
+ WHERE attachmentsProcessed IS NULL
+ """
+ params = []
+ if CREATED_AFTER:
+ sql += " AND createdAt >= %s"
+ params.append(CREATED_AFTER)
+
+ with conn.cursor() as cur:
+ cur.execute(sql, params)
+ rows = cur.fetchall()
+
+ print(f"📋 Found {len(rows)} pozadavky to process (attachmentsProcessed IS NULL"
+ + (f", created >= {CREATED_AFTER}" if CREATED_AFTER else "") + ")")
+
+ for i, row in enumerate(rows, 1):
+ time.sleep(1) # polite API delay
+ req_id = row["id"]
+ prijmeni = row.get("pacient_prijmeni") or "Neznamy"
+ jmeno = row.get("pacient_jmeno") or ""
+ created = row.get("createdAt")
+
+ try:
+ created_date = datetime.strptime(str(created), "%Y-%m-%d %H:%M:%S")
+ except Exception:
+ created_date = None
+
+ print(f"\n[{i}/{len(rows)}] 🧾 {prijmeni}, {jmeno} ({req_id})")
+
+ attachments = fetch_attachments(headers, req_id)
+ if not attachments:
+ print(" ⚠️ No attachments found")
+ with conn.cursor() as cur:
+ cur.execute("UPDATE pozadavky SET attachmentsProcessed = NOW() WHERE id = %s", (req_id,))
+ conn.commit()
+ continue
+
+ with conn.cursor() as cur:
+ for a in attachments:
+ m = a.get("medicalRecord") or {}
+ insert_download(cur, req_id, a, m, jmeno, prijmeni, created_date, existing_ids)
+ conn.commit()
+
+ # ✅ mark processed
+ with conn.cursor() as cur:
+ cur.execute("UPDATE pozadavky SET attachmentsProcessed = NOW() WHERE id = %s", (req_id,))
+ conn.commit()
+
+ print(f" ✅ {len(attachments)} attachments processed for {prijmeni}, {jmeno}")
+ time.sleep(0.3) # polite API delay
+
+ conn.close()
+ print("\n✅ Done! All new attachments processed and pozadavky updated.")
+
+# ==============================
+if __name__ == "__main__":
+ main()
diff --git a/10ReadPozadavky/ReadPozadavkySaveMySql.py b/10ReadPozadavky/ReadPozadavkySaveMySql.py
index 42f4775..39ba8fa 100644
--- a/10ReadPozadavky/ReadPozadavkySaveMySql.py
+++ b/10ReadPozadavky/ReadPozadavkySaveMySql.py
@@ -8,12 +8,12 @@ from datetime import datetime
import time
import time, socket
-for _ in range(30):
- try:
- socket.create_connection(("127.0.0.1", 3307), timeout=3).close()
- break
- except OSError:
- time.sleep(10)
+# for _ in range(30):
+# try:
+# socket.create_connection(("127.0.0.1", 3307), timeout=3).close()
+# break
+# except OSError:
+# time.sleep(10)
# ================================
# 🔧 CONFIGURATION
# ================================
@@ -23,7 +23,8 @@ BATCH_SIZE = 100
DONE_LIMIT = 200 # only last 200 DONE
DB_CONFIG = {
- "host": "127.0.0.1",
+ # "host": "127.0.0.1",
+ "host": "192.168.1.76",
"port": 3307,
"user": "root",
"password": "Vlado9674+",