Initial commit — clean history (removed large test files, browser profiles, Medidata/Clario downloads)
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
EmailMessagingGraph.py
|
||||
----------------------
|
||||
Private Microsoft Graph mail sender
|
||||
Application permissions, shared mailbox
|
||||
"""
|
||||
|
||||
import base64
|
||||
import msal
|
||||
import requests
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
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,
|
||||
attachments: Union[str, Path, List[Union[str, Path]], None] = None,
|
||||
):
|
||||
"""
|
||||
Send email via Microsoft Graph.
|
||||
|
||||
:param to: email or list of emails
|
||||
:param subject: subject
|
||||
:param body: email body (default empty)
|
||||
:param html: True = HTML, False = plain text
|
||||
:param attachments: file path or list of file paths to attach
|
||||
"""
|
||||
|
||||
if isinstance(to, str):
|
||||
to = [to]
|
||||
|
||||
if attachments is None:
|
||||
attachments = []
|
||||
elif isinstance(attachments, (str, Path)):
|
||||
attachments = [attachments]
|
||||
|
||||
attachment_payloads = []
|
||||
for path in attachments:
|
||||
path = Path(path)
|
||||
attachment_payloads.append({
|
||||
"@odata.type": "#microsoft.graph.fileAttachment",
|
||||
"name": path.name,
|
||||
"contentType": "application/octet-stream",
|
||||
"contentBytes": base64.b64encode(path.read_bytes()).decode(),
|
||||
})
|
||||
|
||||
payload = {
|
||||
"message": {
|
||||
"subject": subject,
|
||||
"body": {
|
||||
"contentType": "HTML" if html else "Text",
|
||||
"content": body,
|
||||
},
|
||||
"toRecipients": [
|
||||
{"emailAddress": {"address": addr}} for addr in to
|
||||
],
|
||||
**({"attachments": attachment_payloads} if attachment_payloads else {}),
|
||||
},
|
||||
"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}"
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
import winreg
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
def get_dropbox_root() -> str:
|
||||
"""
|
||||
Vrátí kořenovou cestu složky Dropbox na tomto počítači.
|
||||
|
||||
Dropbox může být nainstalován na různých discích (C:, U:, Z: …),
|
||||
ale struktura složek uvnitř zůstává vždy stejná. Tato funkce zjistí
|
||||
aktuální umístění, takže ostatní skripty nemusí cestu napevno zadávat.
|
||||
|
||||
Postup hledání (v tomto pořadí):
|
||||
1. Registr HKCU\\Software\\Dropbox\\ks — hlavní klíč, hodnota "Personal"
|
||||
je uložena jako byte array v kódování UTF-16 LE.
|
||||
2. Registr HKCU\\Software\\Dropbox\\ks1 — alternativní klíč používaný
|
||||
novějšími verzemi klienta Dropbox.
|
||||
3. Soubor info.json v %APPDATA%\\Dropbox\\ nebo %LOCALAPPDATA%\\Dropbox\\
|
||||
— záložní metoda, pokud registr cestu neobsahuje.
|
||||
|
||||
Vrací:
|
||||
str: Absolutní cesta ke kořenové složce Dropboxu, např. "U:\\Dropbox".
|
||||
|
||||
Vyvolá:
|
||||
RuntimeError: Pokud se cestu nepodaří zjistit žádnou z metod.
|
||||
|
||||
Příklad použití:
|
||||
from Knihovny.najdi_dropbox import get_dropbox_root
|
||||
import os
|
||||
|
||||
ROOT = get_dropbox_root()
|
||||
PACIENTI = os.path.join(ROOT, "Ordinace", "Pacienti")
|
||||
"""
|
||||
|
||||
# Metoda 1 a 2: registr HKCU\Software\Dropbox\ks a ks1
|
||||
for subkey in (r"Software\Dropbox\ks", r"Software\Dropbox\ks1"):
|
||||
try:
|
||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, subkey) as key:
|
||||
value, _ = winreg.QueryValueEx(key, "Personal")
|
||||
path = bytes(value).decode("utf-16-le").rstrip("\x00")
|
||||
if path:
|
||||
return path
|
||||
except (OSError, UnicodeDecodeError):
|
||||
continue
|
||||
|
||||
# Metoda 3: záložní — info.json v AppData
|
||||
for base in (os.getenv("APPDATA", ""), os.getenv("LOCALAPPDATA", "")):
|
||||
info_path = os.path.join(base, "Dropbox", "info.json")
|
||||
if os.path.isfile(info_path):
|
||||
with open(info_path, encoding="utf-8") as f:
|
||||
info = json.load(f)
|
||||
path = (info.get("personal") or info.get("business") or {}).get("path", "")
|
||||
if path:
|
||||
return path
|
||||
|
||||
raise RuntimeError("Nepodařilo se zjistit cestu k Dropboxu.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = get_dropbox_root()
|
||||
print(f"Dropbox root: {root}")
|
||||
Reference in New Issue
Block a user