notebook
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
backfill_entry_id.py | v1.0 | 2026-06-08
|
||||
Dohledá entry_id pro záznamy v jnjemails.db které ho nemají (69k starých emailů
|
||||
přenesených skriptem v1.1). Prochází celý Outlook MAPI strom a páruje emaily
|
||||
dle Internet Message-ID.
|
||||
|
||||
Spouštět na JNJ PC s běžícím Outlookem.
|
||||
Bezpečné opakovat — přeskočí záznamy které už entry_id mají.
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import win32com.client
|
||||
from datetime import datetime
|
||||
|
||||
DB_PATH = r"C:\Users\vbuzalka\SQLITE\jnjemails.db"
|
||||
PR_INTERNET_MESSAGE_ID = "http://schemas.microsoft.com/mapi/proptag/0x1035001E"
|
||||
|
||||
|
||||
def load_missing(conn) -> dict:
|
||||
"""Vrátí dict {message_id: db_id} pro záznamy bez entry_id."""
|
||||
rows = conn.execute(
|
||||
"SELECT id, message_id FROM messages WHERE entry_id IS NULL"
|
||||
).fetchall()
|
||||
return {r[1]: r[0] for r in rows}
|
||||
|
||||
|
||||
def update_entry_id(conn, db_id: int, entry_id: str):
|
||||
conn.execute(
|
||||
"UPDATE messages SET entry_id = ? WHERE id = ?",
|
||||
(entry_id, db_id)
|
||||
)
|
||||
|
||||
|
||||
def scan_folder(conn, folder, lookup: dict, stats: dict, path: str = ""):
|
||||
current = f"{path}/{folder.Name}"
|
||||
try:
|
||||
items = folder.Items
|
||||
for item in items:
|
||||
try:
|
||||
if not item.MessageClass.upper().startswith("IPM.NOTE"):
|
||||
continue
|
||||
|
||||
stats["checked"] += 1
|
||||
|
||||
try:
|
||||
mid = item.PropertyAccessor.GetProperty(PR_INTERNET_MESSAGE_ID)
|
||||
except Exception:
|
||||
mid = None
|
||||
if not mid:
|
||||
mid = f"entryid:{item.EntryID}"
|
||||
|
||||
if mid in lookup:
|
||||
db_id = lookup.pop(mid)
|
||||
update_entry_id(conn, db_id, item.EntryID)
|
||||
stats["updated"] += 1
|
||||
if stats["updated"] % 100 == 0:
|
||||
conn.commit()
|
||||
print(f" [{datetime.now().strftime('%H:%M:%S')}] "
|
||||
f"aktualizováno {stats['updated']} | "
|
||||
f"zbývá {len(lookup)} | složka: {current}")
|
||||
|
||||
except Exception as e:
|
||||
stats["errors"] += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f" CHYBA složka {current}: {e}")
|
||||
stats["errors"] += 1
|
||||
return # nelze ani procházet podsložky
|
||||
|
||||
try:
|
||||
subfolders = list(folder.Folders)
|
||||
except Exception as e:
|
||||
print(f" CHYBA podsložky {current}: {e}")
|
||||
return
|
||||
|
||||
for subfolder in subfolders:
|
||||
if not lookup:
|
||||
return
|
||||
scan_folder(conn, subfolder, lookup, stats, current)
|
||||
|
||||
|
||||
def main():
|
||||
print(f"=== backfill_entry_id v1.0 ===")
|
||||
print(f"Start: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
lookup = load_missing(conn)
|
||||
total_missing = len(lookup)
|
||||
print(f"Záznamy bez entry_id: {total_missing}")
|
||||
|
||||
if not lookup:
|
||||
print("Nic k doplnění.")
|
||||
conn.close()
|
||||
return
|
||||
|
||||
outlook = win32com.client.Dispatch("Outlook.Application")
|
||||
ns = outlook.GetNamespace("MAPI")
|
||||
|
||||
stats = {"checked": 0, "updated": 0, "errors": 0}
|
||||
|
||||
for i in range(1, ns.Folders.Count + 1):
|
||||
if not lookup:
|
||||
break
|
||||
root = ns.Folders.Item(i)
|
||||
print(f"\nSložka: {root.Name}")
|
||||
scan_folder(conn, root, lookup, stats, "")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print(f"\n=== Hotovo ===")
|
||||
print(f"Zkontrolováno emailů: {stats['checked']}")
|
||||
print(f"Doplněno entry_id: {stats['updated']} / {total_missing}")
|
||||
print(f"Nenalezeno: {len(lookup)}")
|
||||
print(f"Chyby: {stats['errors']}")
|
||||
print(f"Konec: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user