122 lines
4.1 KiB
Python
122 lines
4.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# =============================================================================
|
|
# Nazev: backfill_send_failed_v1.0.py
|
|
# Verze: 1.0
|
|
# Datum: 2026-06-17
|
|
# Popis: Jednorazovy backfill. Pro Sent-Items dokumenty bez Internet
|
|
# Message-ID (_id zacina "filename:") v Mongo emaily."vbuzalka@its.jnj.com"
|
|
# precte z odpovidajici .msg na Toweru (/mnt/user/JNJEMAILS) MAPI
|
|
# PrimarySendAccount (0x0E28) + SentRepresenting (0x0065) a nastavi:
|
|
# send_account = hodnota 0x0E28
|
|
# send_failed = True, kdyz obsahuje buzalka.cz (SendAs past)
|
|
# send_error = "SendAs buzalka.cz (PrimarySendAccount)"
|
|
# -> rychly dotaz na NEODESLANE: { send_failed: true }
|
|
# Pouziti: python backfill_send_failed_v1.0.py (dry-run / nahled)
|
|
# python backfill_send_failed_v1.0.py --apply (zapise do Mongo)
|
|
# Pozn.: Cte .msg pres SFTP (paramiko) primo do pameti (BytesIO + olefile).
|
|
# =============================================================================
|
|
|
|
import io
|
|
import sys
|
|
import paramiko
|
|
import olefile
|
|
from pymongo import MongoClient
|
|
|
|
MONGO_URI = "mongodb://192.168.1.76:27017"
|
|
DBN, COL = "emaily", "vbuzalka@its.jnj.com"
|
|
TOWER_HOST, TOWER_USER, TOWER_PASS = "192.168.1.76", "root", "7309208104"
|
|
REMOTE_DIR = "/mnt/user/JNJEMAILS"
|
|
|
|
|
|
def ole_str(ole, tag4):
|
|
for t in (tag4 + "001F", tag4 + "001E"):
|
|
name = "__substg1.0_" + t
|
|
if ole.exists(name):
|
|
b = ole.openstream(name).read()
|
|
if t.endswith("001F"):
|
|
try:
|
|
return b.decode("utf-16-le").strip()
|
|
except Exception:
|
|
pass
|
|
for enc in ("cp1250", "cp1252", "utf-8", "latin-1"):
|
|
try:
|
|
return b.decode(enc).strip()
|
|
except Exception:
|
|
continue
|
|
return ""
|
|
|
|
|
|
def main():
|
|
apply = "--apply" in sys.argv
|
|
cli = MongoClient(MONGO_URI)
|
|
col = cli[DBN][COL]
|
|
|
|
docs = list(col.find(
|
|
{"jnj_folder": {"$regex": "Sent Items"}, "_id": {"$regex": "^filename:"}},
|
|
{"_id": 1, "filename": 1, "to": 1, "subject": 1}))
|
|
print(f"Sent-Items bez Message-ID (filename:): {len(docs)}")
|
|
|
|
ssh = paramiko.SSHClient()
|
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
ssh.connect(TOWER_HOST, username=TOWER_USER, password=TOWER_PASS, timeout=30)
|
|
sftp = ssh.open_sftp()
|
|
|
|
n_buz = n_other = n_missing = 0
|
|
updates = []
|
|
for d in docs:
|
|
fn = d.get("filename")
|
|
if not fn:
|
|
n_missing += 1
|
|
continue
|
|
try:
|
|
raw = sftp.open(f"{REMOTE_DIR}/{fn}", "rb").read()
|
|
ole = olefile.OleFileIO(io.BytesIO(raw))
|
|
except Exception as e:
|
|
print(f" !! {fn}: {e}")
|
|
n_missing += 1
|
|
continue
|
|
try:
|
|
send_acct = ole_str(ole, "0E28")
|
|
sentrep = ole_str(ole, "0065")
|
|
finally:
|
|
ole.close()
|
|
|
|
blob = (send_acct + " " + sentrep).lower()
|
|
is_buz = "buzalka.cz" in blob
|
|
if is_buz:
|
|
n_buz += 1
|
|
err = "SendAs buzalka.cz (PrimarySendAccount)"
|
|
else:
|
|
n_other += 1
|
|
err = None
|
|
updates.append((d["_id"], send_acct, is_buz, err, d.get("to")))
|
|
|
|
sftp.close(); ssh.close()
|
|
|
|
print(f" buzalka.cz (send_failed=True): {n_buz}")
|
|
print(f" jine send-account (False): {n_other}")
|
|
print(f" chybi soubor/cteni: {n_missing}")
|
|
print()
|
|
for _id, acct, is_buz, err, to in updates[:10]:
|
|
print(f" [{'FAIL' if is_buz else 'ok '}] {to} | acct={acct[:60]}")
|
|
if len(updates) > 10:
|
|
print(f" ... a dalsich {len(updates)-10}")
|
|
|
|
if not apply:
|
|
print("\n>>> DRY-RUN. Pro zapis spust s --apply")
|
|
return
|
|
|
|
n = 0
|
|
for _id, acct, is_buz, err, to in updates:
|
|
res = col.update_one({"_id": _id}, {"$set": {
|
|
"send_account": acct,
|
|
"send_failed": bool(is_buz),
|
|
"send_error": err,
|
|
}})
|
|
n += res.modified_count
|
|
print(f"\n>>> ZAPSANO (modified): {n}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|