notebookvb
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# =========================
|
||||
# CONFIG – TEST PC
|
||||
# =========================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
DB = r"localhost/3050:Z:\Medicus 3\data\MEDICUS.FDB"
|
||||
BACKUP_DIR = Path(r"D:\medicusbackup")
|
||||
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
# =========================
|
||||
# MAIN
|
||||
# =========================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
fbk = BACKUP_DIR / f"MEDICUS_{ts}.fbk"
|
||||
log = BACKUP_DIR / f"MEDICUS_{ts}.log"
|
||||
|
||||
cmd = [
|
||||
GBAK,
|
||||
"-b",
|
||||
"-user", FB_USER,
|
||||
"-pas", FB_PASS,
|
||||
DB,
|
||||
str(fbk),
|
||||
"-v",
|
||||
]
|
||||
|
||||
try:
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(
|
||||
cmd,
|
||||
stdout=f,
|
||||
stderr=subprocess.STDOUT,
|
||||
check=True,
|
||||
)
|
||||
|
||||
send_mail(
|
||||
MAIL_TO,
|
||||
"✅ MEDICUS – záloha OK (test PC)",
|
||||
f"""Záloha MEDICUS proběhla úspěšně.
|
||||
|
||||
Čas: {now}
|
||||
Soubor: {fbk}
|
||||
Log: {log}
|
||||
""",
|
||||
)
|
||||
|
||||
except Exception:
|
||||
err = traceback.format_exc()
|
||||
|
||||
send_mail(
|
||||
MAIL_TO,
|
||||
"❌ MEDICUS – CHYBA ZÁLOHY (test PC)",
|
||||
f"""Při záloze MEDICUS došlo k chybě.
|
||||
|
||||
Čas: {now}
|
||||
|
||||
Chyba:
|
||||
{err}
|
||||
|
||||
Log:
|
||||
{log}
|
||||
""",
|
||||
)
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,23 @@
|
||||
from pathlib import Path
|
||||
import zipfile
|
||||
|
||||
# =========================
|
||||
# CONFIG
|
||||
# =========================
|
||||
|
||||
SRC = Path(r"D:\medicusbackup\MEDICUS_2026-01-24_17-07-44.fbk")
|
||||
DST = SRC.with_suffix(".zip")
|
||||
|
||||
# =========================
|
||||
# ZIP MAX COMPRESSION
|
||||
# =========================
|
||||
|
||||
with zipfile.ZipFile(
|
||||
DST,
|
||||
mode="w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9
|
||||
) as z:
|
||||
z.write(SRC, arcname=SRC.name)
|
||||
|
||||
print(f"ZIP created: {DST}")
|
||||
@@ -0,0 +1,39 @@
|
||||
from pathlib import Path
|
||||
import zipfile
|
||||
|
||||
SRC = Path(r"D:\medicusbackup\MEDICUS_2026-01-24_17-07-44.fbk")
|
||||
DST = SRC.with_suffix(".zip")
|
||||
|
||||
total = SRC.stat().st_size
|
||||
processed = 0
|
||||
chunk = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
with zipfile.ZipFile(
|
||||
DST,
|
||||
"w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9,
|
||||
) as zf:
|
||||
|
||||
zi = zipfile.ZipInfo(SRC.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
|
||||
# ⬇⬇⬇ DŮLEŽITÉ ⬇⬇⬇
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(SRC, "rb") as f:
|
||||
while True:
|
||||
buf = f.read(chunk)
|
||||
if not buf:
|
||||
break
|
||||
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
|
||||
pct = processed * 100 / total
|
||||
print(
|
||||
f"\rZIP: {pct:6.2f}% ({processed//1024//1024} MB)",
|
||||
end="",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
print("\nHotovo.")
|
||||
@@ -0,0 +1,141 @@
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
import zipfile
|
||||
import zstandard as zstd
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
SRC = Path(r"D:\medicusbackup\MEDICUS_2026-01-24_17-07-44.fbk")
|
||||
BASE = SRC.with_suffix("")
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
SEVENZIP_EXE = r"c:\Program Files (x86)\7-Zip\7z.exe"
|
||||
|
||||
ORIG_SIZE = SRC.stat().st_size
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ZIP (ZIP64 + progress)
|
||||
# ============================================================
|
||||
|
||||
def zip_test():
|
||||
dst = BASE.with_suffix(".zip")
|
||||
total = ORIG_SIZE
|
||||
processed = 0
|
||||
|
||||
start = time.time()
|
||||
|
||||
with zipfile.ZipFile(
|
||||
dst,
|
||||
"w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9,
|
||||
) as zf:
|
||||
|
||||
zi = zipfile.ZipInfo(SRC.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
|
||||
# ⬇⬇⬇ KLÍČOVÁ OPRAVA ⬇⬇⬇
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(SRC, "rb") as f:
|
||||
while buf := f.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
print(
|
||||
f"\rZIP {processed*100/total:6.2f}%",
|
||||
end="",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
print()
|
||||
return time.time() - start, dst.stat().st_size
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 7Z (CLI + progress)
|
||||
# ============================================================
|
||||
|
||||
def sevenzip_test():
|
||||
dst = BASE.with_suffix(".7z")
|
||||
|
||||
start = time.time()
|
||||
|
||||
proc = subprocess.Popen(
|
||||
[SEVENZIP_EXE, "a", "-t7z", "-mx=9", str(dst), str(SRC)],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
)
|
||||
|
||||
for line in proc.stdout:
|
||||
if "%" in line:
|
||||
print(f"\r7Z {line.strip():>6}", end="", flush=True)
|
||||
|
||||
proc.wait()
|
||||
print()
|
||||
|
||||
return time.time() - start, dst.stat().st_size
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ZSTD (stream + progress)
|
||||
# ============================================================
|
||||
|
||||
def zstd_test():
|
||||
dst = BASE.with_suffix(".zst")
|
||||
total = ORIG_SIZE
|
||||
processed = 0
|
||||
|
||||
cctx = zstd.ZstdCompressor(level=19)
|
||||
start = time.time()
|
||||
|
||||
with open(SRC, "rb") as src, open(dst, "wb") as out:
|
||||
with cctx.stream_writer(out) as compressor:
|
||||
while buf := src.read(CHUNK):
|
||||
compressor.write(buf)
|
||||
processed += len(buf)
|
||||
print(
|
||||
f"\rZSTD {processed*100/total:6.2f}%",
|
||||
end="",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
print()
|
||||
return time.time() - start, dst.stat().st_size
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
results = {}
|
||||
|
||||
print("\n--- ZIP ---")
|
||||
t, s = zip_test()
|
||||
results["ZIP"] = (t, s)
|
||||
|
||||
# print("\n--- 7Z ---")
|
||||
# t, s = sevenzip_test()
|
||||
# results["7Z"] = (t, s)
|
||||
#
|
||||
# print("\n--- ZSTD ---")
|
||||
# t, s = zstd_test()
|
||||
# results["ZSTD"] = (t, s)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SUMMARY
|
||||
# ============================================================
|
||||
|
||||
print("\n=== SUMMARY ===")
|
||||
for name, (t, size) in results.items():
|
||||
ratio = 100 * (1 - size / ORIG_SIZE)
|
||||
print(
|
||||
f"{name:5s}: "
|
||||
f"{t:7.1f} s "
|
||||
f"{size/1024/1024:8.1f} MB "
|
||||
f"(-{ratio:5.1f} %)"
|
||||
)
|
||||
@@ -0,0 +1,161 @@
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
DB = r"localhost/3050:Z:\Medicus 3\data\MEDICUS.FDB"
|
||||
BACKUP_DIR = Path(r"D:\medicusbackup")
|
||||
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
fbk = BACKUP_DIR / f"MEDICUS_{ts}.fbk"
|
||||
zipf = fbk.with_suffix(".zip")
|
||||
log = BACKUP_DIR / f"MEDICUS_{ts}.log"
|
||||
|
||||
report = []
|
||||
report.append(f"Čas spuštění: {now}")
|
||||
report.append(f"Databáze: {DB}")
|
||||
report.append("")
|
||||
|
||||
try:
|
||||
# ====================================================
|
||||
# 1) GBAK
|
||||
# ====================================================
|
||||
t0 = time.time()
|
||||
|
||||
cmd = [
|
||||
GBAK,
|
||||
"-b",
|
||||
"-user", FB_USER,
|
||||
"-pas", FB_PASS,
|
||||
DB,
|
||||
str(fbk),
|
||||
"-v",
|
||||
]
|
||||
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(
|
||||
cmd,
|
||||
stdout=f,
|
||||
stderr=subprocess.STDOUT,
|
||||
check=True,
|
||||
)
|
||||
|
||||
t_gbak = time.time() - t0
|
||||
fbk_size = fbk.stat().st_size
|
||||
|
||||
report.append("GBAK záloha: OK")
|
||||
report.append(f"FBK soubor: {fbk}")
|
||||
report.append(f"Velikost FBK: {fbk_size/1024/1024:.1f} MB")
|
||||
report.append(f"Čas GBAK: {t_gbak:.1f} s")
|
||||
report.append("")
|
||||
|
||||
# ====================================================
|
||||
# 2) ZIP
|
||||
# ====================================================
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
|
||||
with zipfile.ZipFile(
|
||||
zipf,
|
||||
"w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9,
|
||||
) as zf:
|
||||
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(
|
||||
f"\rZIP: {pct:6.2f}% "
|
||||
f"({processed//1024//1024} MB)",
|
||||
end="",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
print("\nZIP hotov.")
|
||||
|
||||
t_zip = time.time() - t1
|
||||
zip_size = zipf.stat().st_size
|
||||
|
||||
report.append("ZIP komprese: OK")
|
||||
report.append(f"ZIP soubor: {zipf}")
|
||||
report.append(f"Velikost ZIP: {zip_size/1024/1024:.1f} MB")
|
||||
report.append(
|
||||
f"Kompresní poměr: "
|
||||
f"{100 * (1 - zip_size / fbk_size):.1f} %"
|
||||
)
|
||||
report.append(f"Čas ZIP: {t_zip:.1f} s")
|
||||
report.append("")
|
||||
|
||||
# ====================================================
|
||||
# 3) DELETE FBK
|
||||
# ====================================================
|
||||
fbk.unlink()
|
||||
|
||||
report.append("FBK soubor byl po úspěšné kompresi smazán.")
|
||||
report.append("")
|
||||
report.append(f"LOG: {log}")
|
||||
|
||||
# ====================================================
|
||||
# MAIL OK
|
||||
# ====================================================
|
||||
send_mail(
|
||||
MAIL_TO,
|
||||
"✅ MEDICUS – záloha + ZIP OK",
|
||||
"\n".join(report),
|
||||
)
|
||||
|
||||
except Exception:
|
||||
err = traceback.format_exc()
|
||||
|
||||
send_mail(
|
||||
MAIL_TO,
|
||||
"❌ MEDICUS – chyba při záloze / ZIP",
|
||||
f"""Při záloze MEDICUS došlo k chybě.
|
||||
|
||||
Čas: {now}
|
||||
|
||||
Chyba:
|
||||
{err}
|
||||
|
||||
FBK (pokud existuje): {fbk}
|
||||
LOG: {log}
|
||||
""",
|
||||
)
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,161 @@
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
DB = r"localhost/3050:Z:\Medicus 3\data\MEDICUS.FDB"
|
||||
BACKUP_DIR = Path(r"D:\medicusbackup")
|
||||
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
fbk = BACKUP_DIR / f"MEDICUS_{ts}.fbk"
|
||||
zipf = fbk.with_suffix(".zip")
|
||||
log = BACKUP_DIR / f"MEDICUS_{ts}.log"
|
||||
|
||||
report = []
|
||||
report.append(f"Čas spuštění: {now}")
|
||||
report.append(f"Databáze: {DB}")
|
||||
report.append("")
|
||||
|
||||
try:
|
||||
# ====================================================
|
||||
# 1) GBAK
|
||||
# ====================================================
|
||||
t0 = time.time()
|
||||
|
||||
cmd = [
|
||||
GBAK,
|
||||
"-b",
|
||||
"-user", FB_USER,
|
||||
"-pas", FB_PASS,
|
||||
DB,
|
||||
str(fbk),
|
||||
"-v",
|
||||
]
|
||||
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(
|
||||
cmd,
|
||||
stdout=f,
|
||||
stderr=subprocess.STDOUT,
|
||||
check=True,
|
||||
)
|
||||
|
||||
t_gbak = time.time() - t0
|
||||
fbk_size = fbk.stat().st_size
|
||||
|
||||
report.append("GBAK záloha: OK")
|
||||
report.append(f"FBK soubor: {fbk}")
|
||||
report.append(f"Velikost FBK: {fbk_size/1024/1024:.1f} MB")
|
||||
report.append(f"Čas GBAK: {t_gbak:.1f} s")
|
||||
report.append("")
|
||||
|
||||
# ====================================================
|
||||
# 2) ZIP
|
||||
# ====================================================
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
|
||||
with zipfile.ZipFile(
|
||||
zipf,
|
||||
"w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9,
|
||||
) as zf:
|
||||
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(
|
||||
f"\rZIP: {pct:6.2f}% "
|
||||
f"({processed//1024//1024} MB)",
|
||||
end="",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
print("\nZIP hotov.")
|
||||
|
||||
t_zip = time.time() - t1
|
||||
zip_size = zipf.stat().st_size
|
||||
|
||||
report.append("ZIP komprese: OK")
|
||||
report.append(f"ZIP soubor: {zipf}")
|
||||
report.append(f"Velikost ZIP: {zip_size/1024/1024:.1f} MB")
|
||||
report.append(
|
||||
f"Kompresní poměr: "
|
||||
f"{100 * (1 - zip_size / fbk_size):.1f} %"
|
||||
)
|
||||
report.append(f"Čas ZIP: {t_zip:.1f} s")
|
||||
report.append("")
|
||||
|
||||
# ====================================================
|
||||
# 3) DELETE FBK
|
||||
# ====================================================
|
||||
fbk.unlink()
|
||||
|
||||
report.append("FBK soubor byl po úspěšné kompresi smazán.")
|
||||
report.append("")
|
||||
report.append(f"LOG: {log}")
|
||||
|
||||
# ====================================================
|
||||
# MAIL OK
|
||||
# ====================================================
|
||||
send_mail(
|
||||
MAIL_TO,
|
||||
"✅ MEDICUS – záloha + ZIP OK",
|
||||
"\n".join(report),
|
||||
)
|
||||
|
||||
except Exception:
|
||||
err = traceback.format_exc()
|
||||
|
||||
send_mail(
|
||||
MAIL_TO,
|
||||
"❌ MEDICUS – chyba při záloze / ZIP",
|
||||
f"""Při záloze MEDICUS došlo k chybě.
|
||||
|
||||
Čas: {now}
|
||||
|
||||
Chyba:
|
||||
{err}
|
||||
|
||||
FBK (pokud existuje): {fbk}
|
||||
LOG: {log}
|
||||
""",
|
||||
)
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,185 @@
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
FB_PORT = "3050"
|
||||
|
||||
MAIN_DB = r"localhost/3050:C:\medicus 3\data\MEDICUS.FDB"
|
||||
EXT_DIR = Path(r"U:\externi")
|
||||
BACKUP_DIR = Path(r"U:\medicusbackup")
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HELPERS
|
||||
# ============================================================
|
||||
|
||||
def gbak_and_zip(label: str, db_conn: str, fbk: Path, zipf: Path, log: Path) -> dict:
|
||||
"""
|
||||
Run gbak backup and ZIP the result.
|
||||
Returns a result dict.
|
||||
"""
|
||||
result = {
|
||||
"label": label,
|
||||
"ok": False,
|
||||
"fbk_size": 0,
|
||||
"zip_size": 0,
|
||||
"t_gbak": 0,
|
||||
"t_zip": 0,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
# 1) GBAK
|
||||
print(f"GBAK: {label} ... ", end="", flush=True)
|
||||
t0 = time.time()
|
||||
cmd = [GBAK, "-b", "-user", FB_USER, "-pas", FB_PASS, db_conn, str(fbk), "-v"]
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(cmd, stdout=f, stderr=subprocess.STDOUT, check=True)
|
||||
result["t_gbak"] = time.time() - t0
|
||||
result["fbk_size"] = fbk.stat().st_size
|
||||
print(f"OK ({result['t_gbak']:.0f}s, {result['fbk_size']/1024/1024:.1f} MB)")
|
||||
|
||||
# 2) ZIP
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
fbk_size = result["fbk_size"]
|
||||
with zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(f"\r ZIP {label}: {pct:6.2f}%", end="", flush=True)
|
||||
print()
|
||||
result["t_zip"] = time.time() - t1
|
||||
result["zip_size"] = zipf.stat().st_size
|
||||
|
||||
# 3) Delete FBK + LOG
|
||||
fbk.unlink()
|
||||
log.unlink()
|
||||
|
||||
result["ok"] = True
|
||||
return result
|
||||
|
||||
|
||||
def format_result(r: dict) -> str:
|
||||
ratio = 100 * (1 - r["zip_size"] / r["fbk_size"]) if r["fbk_size"] else 0
|
||||
return (
|
||||
f" {r['label']}: "
|
||||
f"FBK {r['fbk_size']/1024/1024:.1f} MB → "
|
||||
f"ZIP {r['zip_size']/1024/1024:.1f} MB "
|
||||
f"({ratio:.0f}% komprese, "
|
||||
f"gbak {r['t_gbak']:.0f}s, zip {r['t_zip']:.0f}s)"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
backed_up = []
|
||||
errors = []
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 1) Hlavní DB – MEDICUS.FDB
|
||||
# ----------------------------------------------------------
|
||||
fbk = BACKUP_DIR / f"MEDICUS_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"MEDICUS_{ts}.zip"
|
||||
log = BACKUP_DIR / f"MEDICUS_{ts}.log"
|
||||
try:
|
||||
r = gbak_and_zip("MEDICUS", MAIN_DB, fbk, zipf, log)
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": "MEDICUS", "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 2) Externí DB – MEDICUS_FILES_*.fdb
|
||||
# ----------------------------------------------------------
|
||||
fdb_all = sorted(
|
||||
set(EXT_DIR.glob("MEDICUS_FILES_*.fdb")) | set(EXT_DIR.glob("MEDICUS_FILES_*.FDB")),
|
||||
key=lambda p: p.name.lower(),
|
||||
)
|
||||
|
||||
for fdb in fdb_all:
|
||||
name = fdb.stem
|
||||
fbk = BACKUP_DIR / f"{name}_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"{name}_{ts}.zip"
|
||||
log = BACKUP_DIR / f"{name}_{ts}.log"
|
||||
db_conn = f"localhost/{FB_PORT}:{fdb}"
|
||||
try:
|
||||
r = gbak_and_zip(name, db_conn, fbk, zipf, log)
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": name, "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Report
|
||||
# ----------------------------------------------------------
|
||||
total = 1 + len(fdb_all)
|
||||
report = [
|
||||
f"Backup Medicus – {now.strftime('%d.%m.%Y %H:%M')}",
|
||||
f"Celkem DB: {total} | OK: {len(backed_up)} | Chyby: {len(errors)}",
|
||||
f"Výstupní adresář: {BACKUP_DIR}",
|
||||
"",
|
||||
]
|
||||
|
||||
if backed_up:
|
||||
report.append("--- Zálohováno ---")
|
||||
total_zip = sum(r["zip_size"] for r in backed_up)
|
||||
for r in backed_up:
|
||||
report.append(format_result(r))
|
||||
report.append(f" Celková velikost ZIP: {total_zip/1024/1024:.1f} MB")
|
||||
report.append("")
|
||||
|
||||
if errors:
|
||||
report.append("--- CHYBY ---")
|
||||
for e in errors:
|
||||
report.append(f" {e['label']}:\n{e['error']}")
|
||||
report.append("")
|
||||
|
||||
has_errors = bool(errors)
|
||||
subject = (
|
||||
f"{'X' if has_errors else 'OK'} MEDICUS backup "
|
||||
f"{len(backed_up)}/{total}"
|
||||
+ (f" – {len(errors)} chyb" if has_errors else "")
|
||||
)
|
||||
|
||||
send_mail(MAIL_TO, subject, "\n".join(report))
|
||||
print("\n" + "\n".join(report))
|
||||
|
||||
if errors:
|
||||
raise RuntimeError(f"{len(errors)} backup(s) failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,185 @@
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
FB_PORT = "3050"
|
||||
|
||||
MAIN_DB = r"localhost/3050:C:\medicus 3\data\MEDICUS.FDB"
|
||||
EXT_DIR = Path(r"U:\externi")
|
||||
BACKUP_DIR = Path(r"U:\medicusbackup")
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HELPERS
|
||||
# ============================================================
|
||||
|
||||
def gbak_and_zip(label: str, db_conn: str, fbk: Path, zipf: Path, log: Path) -> dict:
|
||||
"""
|
||||
Run gbak backup and ZIP the result.
|
||||
Returns a result dict.
|
||||
"""
|
||||
result = {
|
||||
"label": label,
|
||||
"ok": False,
|
||||
"fbk_size": 0,
|
||||
"zip_size": 0,
|
||||
"t_gbak": 0,
|
||||
"t_zip": 0,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
# 1) GBAK
|
||||
print(f"GBAK: {label} ... ", end="", flush=True)
|
||||
t0 = time.time()
|
||||
cmd = [GBAK, "-b", "-user", FB_USER, "-pas", FB_PASS, db_conn, str(fbk), "-v"]
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(cmd, stdout=f, stderr=subprocess.STDOUT, check=True)
|
||||
result["t_gbak"] = time.time() - t0
|
||||
result["fbk_size"] = fbk.stat().st_size
|
||||
print(f"OK ({result['t_gbak']:.0f}s, {result['fbk_size']/1024/1024:.1f} MB)")
|
||||
|
||||
# 2) ZIP
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
fbk_size = result["fbk_size"]
|
||||
with zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(f"\r ZIP {label}: {pct:6.2f}%", end="", flush=True)
|
||||
print()
|
||||
result["t_zip"] = time.time() - t1
|
||||
result["zip_size"] = zipf.stat().st_size
|
||||
|
||||
# 3) Delete FBK + LOG
|
||||
fbk.unlink()
|
||||
log.unlink()
|
||||
|
||||
result["ok"] = True
|
||||
return result
|
||||
|
||||
|
||||
def format_result(r: dict) -> str:
|
||||
ratio = 100 * (1 - r["zip_size"] / r["fbk_size"]) if r["fbk_size"] else 0
|
||||
return (
|
||||
f" {r['label']}: "
|
||||
f"FBK {r['fbk_size']/1024/1024:.1f} MB → "
|
||||
f"ZIP {r['zip_size']/1024/1024:.1f} MB "
|
||||
f"({ratio:.0f}% komprese, "
|
||||
f"gbak {r['t_gbak']:.0f}s, zip {r['t_zip']:.0f}s)"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
backed_up = []
|
||||
errors = []
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 1) Hlavní DB – MEDICUS.FDB
|
||||
# ----------------------------------------------------------
|
||||
fbk = BACKUP_DIR / f"MEDICUS_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"MEDICUS_{ts}.zip"
|
||||
log = BACKUP_DIR / f"MEDICUS_{ts}.log"
|
||||
try:
|
||||
r = gbak_and_zip("MEDICUS", MAIN_DB, fbk, zipf, log)
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": "MEDICUS", "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 2) Externí DB – MEDICUS_FILES_*.fdb
|
||||
# ----------------------------------------------------------
|
||||
fdb_all = sorted(
|
||||
set(EXT_DIR.glob("MEDICUS_FILES_*.fdb")) | set(EXT_DIR.glob("MEDICUS_FILES_*.FDB")),
|
||||
key=lambda p: p.name.lower(),
|
||||
)
|
||||
|
||||
for fdb in fdb_all:
|
||||
name = fdb.stem
|
||||
fbk = BACKUP_DIR / f"{name}_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"{name}_{ts}.zip"
|
||||
log = BACKUP_DIR / f"{name}_{ts}.log"
|
||||
db_conn = f"localhost/{FB_PORT}:{fdb}"
|
||||
try:
|
||||
r = gbak_and_zip(name, db_conn, fbk, zipf, log)
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": name, "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Report
|
||||
# ----------------------------------------------------------
|
||||
total = 1 + len(fdb_all)
|
||||
report = [
|
||||
f"Backup Medicus – {now.strftime('%d.%m.%Y %H:%M')}",
|
||||
f"Celkem DB: {total} | OK: {len(backed_up)} | Chyby: {len(errors)}",
|
||||
f"Výstupní adresář: {BACKUP_DIR}",
|
||||
"",
|
||||
]
|
||||
|
||||
if backed_up:
|
||||
report.append("--- Zálohováno ---")
|
||||
total_zip = sum(r["zip_size"] for r in backed_up)
|
||||
for r in backed_up:
|
||||
report.append(format_result(r))
|
||||
report.append(f" Celková velikost ZIP: {total_zip/1024/1024:.1f} MB")
|
||||
report.append("")
|
||||
|
||||
if errors:
|
||||
report.append("--- CHYBY ---")
|
||||
for e in errors:
|
||||
report.append(f" {e['label']}:\n{e['error']}")
|
||||
report.append("")
|
||||
|
||||
has_errors = bool(errors)
|
||||
subject = (
|
||||
f"{'X' if has_errors else 'OK'} MEDICUS backup "
|
||||
f"{len(backed_up)}/{total}"
|
||||
+ (f" – {len(errors)} chyb" if has_errors else "")
|
||||
)
|
||||
|
||||
send_mail(MAIL_TO, subject, "\n".join(report))
|
||||
print("\n" + "\n".join(report))
|
||||
|
||||
if errors:
|
||||
raise RuntimeError(f"{len(errors)} backup(s) failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,235 @@
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
FB_PORT = "3050"
|
||||
|
||||
MAIN_DB = r"localhost/3050:C:\medicus 3\data\MEDICUS.FDB"
|
||||
EXT_DIR = Path(r"c:\medicusext")
|
||||
BACKUP_DIR = Path(r"U:\medicusbackup")
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HELPERS
|
||||
# ============================================================
|
||||
|
||||
def run_gbak(label: str, db_conn: str, fbk: Path, log: Path) -> dict:
|
||||
"""Run gbak, return result dict (without zip info)."""
|
||||
result = {
|
||||
"label": label,
|
||||
"ok": False,
|
||||
"fbk": fbk,
|
||||
"fbk_size": 0,
|
||||
"zip_size": 0,
|
||||
"t_gbak": 0,
|
||||
"t_zip": 0,
|
||||
"error": None,
|
||||
}
|
||||
print(f"GBAK: {label} ... ", end="", flush=True)
|
||||
t0 = time.time()
|
||||
cmd = [GBAK, "-b", "-user", FB_USER, "-pas", FB_PASS, db_conn, str(fbk), "-v"]
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(cmd, stdout=f, stderr=subprocess.STDOUT, check=True)
|
||||
result["t_gbak"] = time.time() - t0
|
||||
result["fbk_size"] = fbk.stat().st_size
|
||||
print(f"OK ({result['t_gbak']:.0f}s, {result['fbk_size']/1024/1024:.1f} MB)")
|
||||
result["ok"] = True
|
||||
return result
|
||||
|
||||
|
||||
def zip_single(label: str, fbk: Path, zipf: Path) -> tuple[int, float]:
|
||||
"""ZIP one FBK into its own ZIP. Returns (zip_size, t_zip)."""
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
fbk_size = fbk.stat().st_size
|
||||
with zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(f"\r ZIP {label}: {pct:6.2f}%", end="", flush=True)
|
||||
print()
|
||||
return zipf.stat().st_size, time.time() - t1
|
||||
|
||||
|
||||
def zip_multiple(fbk_results: list[dict], zipf: Path) -> tuple[int, float]:
|
||||
"""ZIP multiple FBK files into one ZIP. Returns (zip_size, t_zip)."""
|
||||
t1 = time.time()
|
||||
total_fbk_size = sum(r["fbk_size"] for r in fbk_results)
|
||||
total_processed = 0
|
||||
with zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
|
||||
for r in fbk_results:
|
||||
fbk = r["fbk"]
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
total_processed += len(buf)
|
||||
pct = total_processed * 100 / total_fbk_size
|
||||
print(f"\r ZIP {fbk.name}: {pct:6.2f}%", end="", flush=True)
|
||||
print()
|
||||
return zipf.stat().st_size, time.time() - t1
|
||||
|
||||
|
||||
def format_result(r: dict) -> str:
|
||||
ratio = 100 * (1 - r["zip_size"] / r["fbk_size"]) if r["fbk_size"] else 0
|
||||
return (
|
||||
f" {r['label']}: "
|
||||
f"FBK {r['fbk_size']/1024/1024:.1f} MB → "
|
||||
f"ZIP {r['zip_size']/1024/1024:.1f} MB "
|
||||
f"({ratio:.0f}% komprese, "
|
||||
f"gbak {r['t_gbak']:.0f}s, zip {r['t_zip']:.0f}s)"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
backed_up = []
|
||||
errors = []
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 1) Hlavní DB – MEDICUS.FDB → vlastní ZIP
|
||||
# ----------------------------------------------------------
|
||||
fbk = BACKUP_DIR / f"MEDICUS_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"MEDICUS_{ts}.zip"
|
||||
log = BACKUP_DIR / f"MEDICUS_{ts}.log"
|
||||
try:
|
||||
r = run_gbak("MEDICUS", MAIN_DB, fbk, log)
|
||||
log.unlink()
|
||||
zip_size, t_zip = zip_single("MEDICUS", fbk, zipf)
|
||||
fbk.unlink()
|
||||
r["zip_size"] = zip_size
|
||||
r["t_zip"] = t_zip
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": "MEDICUS", "fbk_size": 0, "zip_size": 0, "t_gbak": 0, "t_zip": 0, "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 2) Externí DB – MEDICUS_FILES_*.fdb → všechny do jednoho ZIP
|
||||
# ----------------------------------------------------------
|
||||
fdb_all = sorted(
|
||||
set(EXT_DIR.glob("MEDICUS_FILES_*.fdb")) | set(EXT_DIR.glob("MEDICUS_FILES_*.FDB")),
|
||||
key=lambda p: p.name.lower(),
|
||||
)
|
||||
|
||||
ext_results = []
|
||||
for fdb in fdb_all:
|
||||
name = fdb.stem
|
||||
fbk = BACKUP_DIR / f"{name}_{ts}.fbk"
|
||||
log = BACKUP_DIR / f"{name}_{ts}.log"
|
||||
db_conn = f"localhost/{FB_PORT}:{fdb}"
|
||||
try:
|
||||
r = run_gbak(name, db_conn, fbk, log)
|
||||
log.unlink()
|
||||
ext_results.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": name, "fbk_size": 0, "zip_size": 0, "t_gbak": 0, "t_zip": 0, "error": traceback.format_exc()})
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# ZIP všechny externí FBK do jednoho souboru
|
||||
if ext_results:
|
||||
ext_zip = BACKUP_DIR / f"MEDICUS_FILES_{ts}.zip"
|
||||
print(f"\nZIP externích DB → {ext_zip.name}")
|
||||
try:
|
||||
zip_size, t_zip = zip_multiple(ext_results, ext_zip)
|
||||
for r in ext_results:
|
||||
r["zip_size"] = zip_size # sdílená velikost výsledného ZIPu
|
||||
r["t_zip"] = t_zip
|
||||
r["fbk"].unlink()
|
||||
backed_up.append(r)
|
||||
except Exception:
|
||||
errors.append({"label": "MEDICUS_FILES (zip)", "fbk_size": 0, "zip_size": 0, "t_gbak": 0, "t_zip": 0, "error": traceback.format_exc()})
|
||||
for r in ext_results:
|
||||
if r["fbk"].exists():
|
||||
r["fbk"].unlink()
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Report
|
||||
# ----------------------------------------------------------
|
||||
total = 1 + len(fdb_all)
|
||||
report = [
|
||||
f"Backup Medicus – {now.strftime('%d.%m.%Y %H:%M')}",
|
||||
f"Celkem DB: {total} | OK: {len(backed_up)} | Chyby: {len(errors)}",
|
||||
f"Výstupní adresář: {BACKUP_DIR}",
|
||||
"",
|
||||
]
|
||||
|
||||
if backed_up:
|
||||
report.append("--- Zálohováno ---")
|
||||
# Hlavní DB
|
||||
main_results = [r for r in backed_up if r["label"] == "MEDICUS"]
|
||||
ext_backed = [r for r in backed_up if r["label"] != "MEDICUS"]
|
||||
for r in main_results:
|
||||
report.append(format_result(r))
|
||||
if ext_backed:
|
||||
total_ext_fbk = sum(r["fbk_size"] for r in ext_backed)
|
||||
ext_zip_size = ext_backed[0]["zip_size"] if ext_backed else 0
|
||||
ratio = 100 * (1 - ext_zip_size / total_ext_fbk) if total_ext_fbk else 0
|
||||
report.append(f" Externí DB ({len(ext_backed)} souborů):")
|
||||
for r in ext_backed:
|
||||
report.append(f" {r['label']}: FBK {r['fbk_size']/1024/1024:.1f} MB (gbak {r['t_gbak']:.0f}s)")
|
||||
report.append(
|
||||
f" → společný ZIP: {ext_zip_size/1024/1024:.1f} MB "
|
||||
f"({ratio:.0f}% komprese, zip {ext_backed[0]['t_zip']:.0f}s)"
|
||||
)
|
||||
total_zip = sum(r["zip_size"] for r in main_results) + (ext_backed[0]["zip_size"] if ext_backed else 0)
|
||||
report.append(f" Celková velikost ZIP: {total_zip/1024/1024:.1f} MB")
|
||||
report.append("")
|
||||
|
||||
if errors:
|
||||
report.append("--- CHYBY ---")
|
||||
for e in errors:
|
||||
report.append(f" {e['label']}:\n{e['error']}")
|
||||
report.append("")
|
||||
|
||||
has_errors = bool(errors)
|
||||
subject = (
|
||||
f"{'X' if has_errors else 'OK'} MEDICUS backup "
|
||||
f"{len(backed_up)}/{total}"
|
||||
+ (f" – {len(errors)} chyb" if has_errors else "")
|
||||
)
|
||||
|
||||
send_mail(MAIL_TO, subject, "\n".join(report))
|
||||
print("\n" + "\n".join(report))
|
||||
|
||||
if errors:
|
||||
raise RuntimeError(f"{len(errors)} backup(s) failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,172 @@
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
FB_PORT = "3050"
|
||||
|
||||
SRC_DIR = Path(r"c:\medicusext")
|
||||
BACKUP_DIR = Path(r"U:\medicusbackup")
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
# Find all FDB files (case-insensitive)
|
||||
fdb_files = sorted(SRC_DIR.glob("MEDICUS_FILES_*.fdb"))
|
||||
fdb_upper = sorted(SRC_DIR.glob("MEDICUS_FILES_*.FDB"))
|
||||
fdb_all = sorted(
|
||||
set(fdb_files + fdb_upper),
|
||||
key=lambda p: p.name.lower(),
|
||||
)
|
||||
|
||||
backed_up = []
|
||||
errors = []
|
||||
|
||||
for fdb in fdb_all:
|
||||
name = fdb.stem
|
||||
fbk = BACKUP_DIR / f"{name}_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"{name}_{ts}.zip"
|
||||
log = BACKUP_DIR / f"{name}_{ts}.log"
|
||||
|
||||
result = {
|
||||
"file": fdb.name,
|
||||
"ok": False,
|
||||
"fbk_size": 0,
|
||||
"zip_size": 0,
|
||||
"t_gbak": 0,
|
||||
"t_zip": 0,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
try:
|
||||
# 1) GBAK
|
||||
print(f"GBAK: {fdb.name} ... ", end="", flush=True)
|
||||
t0 = time.time()
|
||||
db_conn = f"localhost/{FB_PORT}:{fdb}"
|
||||
cmd = [
|
||||
GBAK, "-b",
|
||||
"-user", FB_USER,
|
||||
"-pas", FB_PASS,
|
||||
db_conn, str(fbk),
|
||||
"-v",
|
||||
]
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(
|
||||
cmd, stdout=f, stderr=subprocess.STDOUT, check=True,
|
||||
)
|
||||
result["t_gbak"] = time.time() - t0
|
||||
result["fbk_size"] = fbk.stat().st_size
|
||||
print(f"OK ({result['t_gbak']:.0f}s)")
|
||||
|
||||
# 2) ZIP
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
fbk_size = result["fbk_size"]
|
||||
|
||||
with zipfile.ZipFile(
|
||||
zipf, "w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9,
|
||||
) as zf:
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(
|
||||
f"\r ZIP {name}: {pct:6.2f}%",
|
||||
end="", flush=True,
|
||||
)
|
||||
print()
|
||||
|
||||
result["t_zip"] = time.time() - t1
|
||||
result["zip_size"] = zipf.stat().st_size
|
||||
|
||||
# 3) DELETE FBK + LOG
|
||||
fbk.unlink()
|
||||
log.unlink()
|
||||
|
||||
result["ok"] = True
|
||||
backed_up.append(result)
|
||||
|
||||
except Exception:
|
||||
result["error"] = traceback.format_exc()
|
||||
errors.append(result)
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# Build report
|
||||
report = []
|
||||
report.append(f"Backup externi DB - {now.strftime('%d.%m.%Y %H:%M')}")
|
||||
report.append(f"Celkem souboru: {len(fdb_all)}")
|
||||
report.append(f"Zalohovano: {len(backed_up)}")
|
||||
report.append(f"Chyby: {len(errors)}")
|
||||
report.append("")
|
||||
|
||||
if backed_up:
|
||||
report.append("--- Backed up ---")
|
||||
total_zip = 0
|
||||
for r in backed_up:
|
||||
total_zip += r["zip_size"]
|
||||
report.append(
|
||||
f" {r['file']}: "
|
||||
f"FBK {r['fbk_size']/1024/1024:.1f} MB -> "
|
||||
f"ZIP {r['zip_size']/1024/1024:.1f} MB "
|
||||
f"(gbak {r['t_gbak']:.0f}s, zip {r['t_zip']:.0f}s)"
|
||||
)
|
||||
report.append(f" Total ZIP: {total_zip / 1024 / 1024:.1f} MB")
|
||||
report.append("")
|
||||
|
||||
if errors:
|
||||
report.append("--- ERRORS ---")
|
||||
for r in errors:
|
||||
report.append(f" {r['file']}: {r['error']}")
|
||||
report.append("")
|
||||
|
||||
# Send email
|
||||
has_errors = len(errors) > 0
|
||||
subject = (
|
||||
f"{'X' if has_errors else 'OK'} "
|
||||
f"MEDICUS externi DB - "
|
||||
f"backup {len(backed_up)}/{len(fdb_all)}"
|
||||
f"{f', {len(errors)} errors' if has_errors else ''}"
|
||||
)
|
||||
|
||||
send_mail(MAIL_TO, subject, "\n".join(report))
|
||||
|
||||
print("\n" + "\n".join(report))
|
||||
|
||||
if errors:
|
||||
raise RuntimeError(f"{len(errors)} backup(s) failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,172 @@
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
FB_PORT = "3050"
|
||||
|
||||
SRC_DIR = Path(r"c:\medicusext")
|
||||
BACKUP_DIR = Path(r"U:\medicusbackup")
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
# Find all FDB files (case-insensitive)
|
||||
fdb_files = sorted(SRC_DIR.glob("MEDICUS_FILES_*.fdb"))
|
||||
fdb_upper = sorted(SRC_DIR.glob("MEDICUS_FILES_*.FDB"))
|
||||
fdb_all = sorted(
|
||||
set(fdb_files + fdb_upper),
|
||||
key=lambda p: p.name.lower(),
|
||||
)
|
||||
|
||||
backed_up = []
|
||||
errors = []
|
||||
|
||||
for fdb in fdb_all:
|
||||
name = fdb.stem
|
||||
fbk = BACKUP_DIR / f"{name}_{ts}.fbk"
|
||||
zipf = BACKUP_DIR / f"{name}_{ts}.zip"
|
||||
log = BACKUP_DIR / f"{name}_{ts}.log"
|
||||
|
||||
result = {
|
||||
"file": fdb.name,
|
||||
"ok": False,
|
||||
"fbk_size": 0,
|
||||
"zip_size": 0,
|
||||
"t_gbak": 0,
|
||||
"t_zip": 0,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
try:
|
||||
# 1) GBAK
|
||||
print(f"GBAK: {fdb.name} ... ", end="", flush=True)
|
||||
t0 = time.time()
|
||||
db_conn = f"localhost/{FB_PORT}:{fdb}"
|
||||
cmd = [
|
||||
GBAK, "-b",
|
||||
"-user", FB_USER,
|
||||
"-pas", FB_PASS,
|
||||
db_conn, str(fbk),
|
||||
"-v",
|
||||
]
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(
|
||||
cmd, stdout=f, stderr=subprocess.STDOUT, check=True,
|
||||
)
|
||||
result["t_gbak"] = time.time() - t0
|
||||
result["fbk_size"] = fbk.stat().st_size
|
||||
print(f"OK ({result['t_gbak']:.0f}s)")
|
||||
|
||||
# 2) ZIP
|
||||
t1 = time.time()
|
||||
processed = 0
|
||||
fbk_size = result["fbk_size"]
|
||||
|
||||
with zipfile.ZipFile(
|
||||
zipf, "w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9,
|
||||
) as zf:
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
processed += len(buf)
|
||||
pct = processed * 100 / fbk_size
|
||||
print(
|
||||
f"\r ZIP {name}: {pct:6.2f}%",
|
||||
end="", flush=True,
|
||||
)
|
||||
print()
|
||||
|
||||
result["t_zip"] = time.time() - t1
|
||||
result["zip_size"] = zipf.stat().st_size
|
||||
|
||||
# 3) DELETE FBK + LOG
|
||||
fbk.unlink()
|
||||
log.unlink()
|
||||
|
||||
result["ok"] = True
|
||||
backed_up.append(result)
|
||||
|
||||
except Exception:
|
||||
result["error"] = traceback.format_exc()
|
||||
errors.append(result)
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# Build report
|
||||
report = []
|
||||
report.append(f"Backup externi DB - {now.strftime('%d.%m.%Y %H:%M')}")
|
||||
report.append(f"Celkem souboru: {len(fdb_all)}")
|
||||
report.append(f"Zalohovano: {len(backed_up)}")
|
||||
report.append(f"Chyby: {len(errors)}")
|
||||
report.append("")
|
||||
|
||||
if backed_up:
|
||||
report.append("--- Backed up ---")
|
||||
total_zip = 0
|
||||
for r in backed_up:
|
||||
total_zip += r["zip_size"]
|
||||
report.append(
|
||||
f" {r['file']}: "
|
||||
f"FBK {r['fbk_size']/1024/1024:.1f} MB -> "
|
||||
f"ZIP {r['zip_size']/1024/1024:.1f} MB "
|
||||
f"(gbak {r['t_gbak']:.0f}s, zip {r['t_zip']:.0f}s)"
|
||||
)
|
||||
report.append(f" Total ZIP: {total_zip / 1024 / 1024:.1f} MB")
|
||||
report.append("")
|
||||
|
||||
if errors:
|
||||
report.append("--- ERRORS ---")
|
||||
for r in errors:
|
||||
report.append(f" {r['file']}: {r['error']}")
|
||||
report.append("")
|
||||
|
||||
# Send email
|
||||
has_errors = len(errors) > 0
|
||||
subject = (
|
||||
f"{'X' if has_errors else 'OK'} "
|
||||
f"MEDICUS externi DB - "
|
||||
f"backup {len(backed_up)}/{len(fdb_all)}"
|
||||
f"{f', {len(errors)} errors' if has_errors else ''}"
|
||||
)
|
||||
|
||||
send_mail(MAIL_TO, subject, "\n".join(report))
|
||||
|
||||
print("\n" + "\n".join(report))
|
||||
|
||||
if errors:
|
||||
raise RuntimeError(f"{len(errors)} backup(s) failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,189 @@
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from EmailMessagingGraph import send_mail
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
GBAK = r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe"
|
||||
FB_USER = "SYSDBA"
|
||||
FB_PASS = "masterkey"
|
||||
FB_PORT = "3050"
|
||||
|
||||
SRC_DIR = Path(r"c:\medicusext")
|
||||
BACKUP_DIR = Path(r"U:\medicusbackup")
|
||||
|
||||
MAIL_TO = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
CHUNK = 8 * 1024 * 1024 # 8 MB
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
now = datetime.now()
|
||||
ts = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||
|
||||
# Find all FDB files (case-insensitive)
|
||||
fdb_files = sorted(SRC_DIR.glob("MEDICUS_FILES_*.fdb"))
|
||||
fdb_upper = sorted(SRC_DIR.glob("MEDICUS_FILES_*.FDB"))
|
||||
fdb_all = sorted(
|
||||
set(fdb_files + fdb_upper),
|
||||
key=lambda p: p.name.lower(),
|
||||
)
|
||||
|
||||
backed_up = []
|
||||
errors = []
|
||||
fbk_paths = [] # FBK files to be zipped together
|
||||
|
||||
# --------------------------------------------------------
|
||||
# 1) GBAK all databases
|
||||
# --------------------------------------------------------
|
||||
for fdb in fdb_all:
|
||||
name = fdb.stem
|
||||
fbk = BACKUP_DIR / f"{name}_{ts}.fbk"
|
||||
log = BACKUP_DIR / f"{name}_{ts}.log"
|
||||
|
||||
result = {
|
||||
"file": fdb.name,
|
||||
"ok": False,
|
||||
"fbk_size": 0,
|
||||
"zip_size": 0,
|
||||
"t_gbak": 0,
|
||||
"t_zip": 0,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
try:
|
||||
print(f"GBAK: {fdb.name} ... ", end="", flush=True)
|
||||
t0 = time.time()
|
||||
db_conn = f"localhost/{FB_PORT}:{fdb}"
|
||||
cmd = [
|
||||
GBAK, "-b",
|
||||
"-user", FB_USER,
|
||||
"-pas", FB_PASS,
|
||||
db_conn, str(fbk),
|
||||
"-v",
|
||||
]
|
||||
with open(log, "w", encoding="utf-8") as f:
|
||||
subprocess.run(
|
||||
cmd, stdout=f, stderr=subprocess.STDOUT, check=True,
|
||||
)
|
||||
result["t_gbak"] = time.time() - t0
|
||||
result["fbk_size"] = fbk.stat().st_size
|
||||
print(f"OK ({result['t_gbak']:.0f}s)")
|
||||
|
||||
# Delete log, keep FBK for zipping
|
||||
log.unlink()
|
||||
|
||||
result["ok"] = True
|
||||
fbk_paths.append((fbk, result))
|
||||
backed_up.append(result)
|
||||
|
||||
except Exception:
|
||||
result["error"] = traceback.format_exc()
|
||||
errors.append(result)
|
||||
for f in (fbk, log):
|
||||
if f.exists():
|
||||
f.unlink()
|
||||
|
||||
# --------------------------------------------------------
|
||||
# 2) ZIP all FBK files into one archive
|
||||
# --------------------------------------------------------
|
||||
total_zip_size = 0
|
||||
if fbk_paths:
|
||||
zip_path = BACKUP_DIR / f"MEDICUS_FILES_{ts}.zip"
|
||||
print(f"\nZIP: {zip_path.name}")
|
||||
t_zip_start = time.time()
|
||||
|
||||
# Calculate total size for progress
|
||||
total_fbk_size = sum(fbk.stat().st_size for fbk, _ in fbk_paths)
|
||||
total_processed = 0
|
||||
|
||||
with zipfile.ZipFile(
|
||||
zip_path, "w",
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9,
|
||||
) as zf:
|
||||
for fbk, result in fbk_paths:
|
||||
zi = zipfile.ZipInfo(fbk.name)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
with zf.open(zi, "w", force_zip64=True) as z:
|
||||
with open(fbk, "rb") as src:
|
||||
while buf := src.read(CHUNK):
|
||||
z.write(buf)
|
||||
total_processed += len(buf)
|
||||
pct = total_processed * 100 / total_fbk_size
|
||||
print(
|
||||
f"\r {fbk.name}: {pct:6.2f}%",
|
||||
end="", flush=True,
|
||||
)
|
||||
print()
|
||||
|
||||
t_zip_total = time.time() - t_zip_start
|
||||
total_zip_size = zip_path.stat().st_size
|
||||
print(f"ZIP OK ({t_zip_total:.0f}s, {total_zip_size/1024/1024:.1f} MB)")
|
||||
|
||||
# Fill zip_size into each result and delete FBK files
|
||||
for fbk, result in fbk_paths:
|
||||
result["zip_size"] = total_zip_size
|
||||
fbk.unlink()
|
||||
|
||||
# --------------------------------------------------------
|
||||
# Build report
|
||||
# --------------------------------------------------------
|
||||
report = []
|
||||
report.append(f"Backup externi DB - {now.strftime('%d.%m.%Y %H:%M')}")
|
||||
report.append(f"Celkem souboru: {len(fdb_all)}")
|
||||
report.append(f"Zalohovano: {len(backed_up)}")
|
||||
report.append(f"Chyby: {len(errors)}")
|
||||
report.append("")
|
||||
|
||||
if backed_up:
|
||||
report.append("--- Backed up ---")
|
||||
total_fbk_mb = sum(r["fbk_size"] for r in backed_up) / 1024 / 1024
|
||||
for r in backed_up:
|
||||
report.append(
|
||||
f" {r['file']}: "
|
||||
f"FBK {r['fbk_size']/1024/1024:.1f} MB "
|
||||
f"(gbak {r['t_gbak']:.0f}s)"
|
||||
)
|
||||
report.append(f" Total FBK: {total_fbk_mb:.1f} MB -> ZIP: {total_zip_size/1024/1024:.1f} MB")
|
||||
report.append("")
|
||||
|
||||
if errors:
|
||||
report.append("--- ERRORS ---")
|
||||
for r in errors:
|
||||
report.append(f" {r['file']}: {r['error']}")
|
||||
report.append("")
|
||||
|
||||
# Send email
|
||||
has_errors = len(errors) > 0
|
||||
subject = (
|
||||
f"{'X' if has_errors else 'OK'} "
|
||||
f"MEDICUS externi DB - "
|
||||
f"backup {len(backed_up)}/{len(fdb_all)}"
|
||||
f"{f', {len(errors)} errors' if has_errors else ''}"
|
||||
)
|
||||
|
||||
send_mail(MAIL_TO, subject, "\n".join(report))
|
||||
|
||||
print("\n" + "\n".join(report))
|
||||
|
||||
if errors:
|
||||
raise RuntimeError(f"{len(errors)} backup(s) failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
Upravená verze skriptu, prosím upravte si cesty, toto vše vložit do nějakého cmd souboru:
|
||||
editují se pouze následující sekce:
|
||||
rem /zalozeni slozek do kterych se ma zalohovat kdyz neexistuji/
|
||||
rem /nastaveni serveru a portu a cest k db/
|
||||
rem /zaloha/ - v případě že je soubor gbak umístěn jinde, je jiná cesta k Firebirdu
|
||||
rem/odkud kam kopirovat/
|
||||
@echo off
|
||||
rem /nacteni aktualniho datumu a casu/
|
||||
For /f "tokens=1-3 delims=/." %%a in ("%DATE%") do (set mydate=%%c-%%b-%%a)
|
||||
For /f "tokens=1-2 delims=/:" %%a in ("%TIME%") do (set mytime=%%a-%%b)
|
||||
@echo on
|
||||
rem /zalozeni slozek do kterych se ma zalohovat kdyz neexistuji/
|
||||
if not exist "C:\zalohy\MEDICUS" mkdir "C:\zalohy\MEDICUS"
|
||||
if not exist "C:\backup\MEDICUS" mkdir "C:\backup\MEDICUS"
|
||||
rem /nastaveni serveru a portu a cest k db/
|
||||
set ufdb="localhost/3050:c:\Medicus\Medicus Komfort\data\sestavy.fdb"
|
||||
rem /nastaveni cesty pro umisteni zalohy/
|
||||
set ufbk="C:\zalohy\MEDICUS\MEDICUS3_%mydate%%mytime%.FBK" -y "C:\zalohy\MEDICUS\log%mydate%_%mytime%.txt"
|
||||
rem /zaloha/
|
||||
"C:\Program Files (x86)\Firebird\Firebird_2_5\bin\gbak" -b -user SYSDBA -pas masterke %ufdb% %ufbk% -v
|
||||
rem/odkud kam kopirovat/
|
||||
set odkud="C:\zalohy\MEDICUS*.*"
|
||||
set kam="C:\backup\MEDICUS"
|
||||
SET drv1=%odkud:~1,1%
|
||||
SET drv2=%kam:~1,1%
|
||||
if %drv1%==%drv2% goto :move
|
||||
if not %drv1%==%drv2% goto :copy
|
||||
:move
|
||||
rem /presunuti do jineho umisteni/
|
||||
move /Y %odkud% %kam%
|
||||
goto :exit
|
||||
:copy
|
||||
rem /kopiruj a smaz/
|
||||
copy /Y %odkud% %kam%
|
||||
del /Q %odkud%
|
||||
goto :exit
|
||||
:exit
|
||||
timeout /T 5
|
||||
exit
|
||||
Zajímavé odkazy rovněž zde:
|
||||
https://docplayer.cz/665150-Databaze-firebird-zalohovani-obnoveni-roman-fic-1-29-14-databaze.html
|
||||
http://www.epos.cz/obis4wiki/firebird:zalohovani_databazi_-_gbak
|
||||
Pohodový den přeje
|
||||
Mgr. Josef Kauc
|
||||
KONZULTANT MEDICUS
|
||||
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
EmailMessagingGraph.py
|
||||
----------------------
|
||||
Private Microsoft Graph mail sender
|
||||
Application permissions, shared mailbox
|
||||
"""
|
||||
|
||||
import msal
|
||||
import requests
|
||||
from functools import lru_cache
|
||||
from typing import Union, List
|
||||
|
||||
|
||||
# =========================
|
||||
# PRIVATE CONFIG (ONLY YOU)
|
||||
# =========================
|
||||
TENANT_ID = "7d269944-37a4-43a1-8140-c7517dc426e9"
|
||||
CLIENT_ID = "4b222bfd-78c9-4239-a53f-43006b3ed07f"
|
||||
CLIENT_SECRET = "Txg8Q~MjhocuopxsJyJBhPmDfMxZ2r5WpTFj1dfk"
|
||||
SENDER = "reports@buzalka.cz"
|
||||
|
||||
|
||||
AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}"
|
||||
SCOPE = ["https://graph.microsoft.com/.default"]
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _get_token() -> str:
|
||||
app = msal.ConfidentialClientApplication(
|
||||
CLIENT_ID,
|
||||
authority=AUTHORITY,
|
||||
client_credential=CLIENT_SECRET,
|
||||
)
|
||||
|
||||
token = app.acquire_token_for_client(scopes=SCOPE)
|
||||
|
||||
if "access_token" not in token:
|
||||
raise RuntimeError(f"Graph auth failed: {token}")
|
||||
|
||||
return token["access_token"]
|
||||
|
||||
|
||||
def send_mail(
|
||||
to: Union[str, List[str]],
|
||||
subject: str,
|
||||
body: str,
|
||||
*,
|
||||
html: bool = False,
|
||||
):
|
||||
"""
|
||||
Send email via Microsoft Graph.
|
||||
|
||||
:param to: email or list of emails
|
||||
:param subject: subject
|
||||
:param body: email body
|
||||
:param html: True = HTML, False = plain text
|
||||
"""
|
||||
|
||||
if isinstance(to, str):
|
||||
to = [to]
|
||||
|
||||
payload = {
|
||||
"message": {
|
||||
"subject": subject,
|
||||
"body": {
|
||||
"contentType": "HTML" if html else "Text",
|
||||
"content": body,
|
||||
},
|
||||
"toRecipients": [
|
||||
{"emailAddress": {"address": addr}} for addr in to
|
||||
],
|
||||
},
|
||||
"saveToSentItems": "true",
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {_get_token()}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
r = requests.post(
|
||||
f"https://graph.microsoft.com/v1.0/users/{SENDER}/sendMail",
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
if r.status_code != 202:
|
||||
raise RuntimeError(
|
||||
f"sendMail failed [{r.status_code}]: {r.text}"
|
||||
)
|
||||
Reference in New Issue
Block a user