diff --git a/EmailsImport/.env b/EmailsImport/.env new file mode 100644 index 0000000..e70d6a6 --- /dev/null +++ b/EmailsImport/.env @@ -0,0 +1,3 @@ +DROPBOX_APP_KEY=4scysbfek6ddwwm +DROPBOX_APP_SECRET=gn9ph1q3oro2nq0 +DROPBOX_APP_REFRESH_TOKEN=VShbST3VjUgAAAAAAAAAAXeZZzFLns6eE80-VJKIc5oq61PyXW6sCx9Dw5kM1w8c \ No newline at end of file diff --git a/EmailsImport/10 GetOneTimeDropBoxAuth.py b/EmailsImport/10 GetOneTimeDropBoxAuth.py new file mode 100644 index 0000000..a785c8d --- /dev/null +++ b/EmailsImport/10 GetOneTimeDropBoxAuth.py @@ -0,0 +1,25 @@ +import dropbox +from dotenv import load_dotenv +from pathlib import Path +import os +from dropbox import DropboxOAuth2FlowNoRedirect + +load_dotenv(Path(__file__).parent / ".env") + +APP_KEY = os.getenv("DROPBOX_APP_KEY", "") +APP_SECRET = os.getenv("DROPBOX_APP_SECRET", "") + +auth_flow = DropboxOAuth2FlowNoRedirect( + APP_KEY, + APP_SECRET, + token_access_type='offline' # důležité — dá refresh token +) + +authorize_url = auth_flow.start() +print(f"Otevři v prohlížeči:\n{authorize_url}") + +auth_code = input("Vlož autorizační kód: ").strip() +oauth_result = auth_flow.finish(auth_code) + +print(f"Refresh token: {oauth_result.refresh_token}") +# Tento token ulož — platí "navždy" (dokud app neodvoláš) \ No newline at end of file diff --git a/EmailsImport/20 TestDropboxUpload.py b/EmailsImport/20 TestDropboxUpload.py new file mode 100644 index 0000000..7994299 --- /dev/null +++ b/EmailsImport/20 TestDropboxUpload.py @@ -0,0 +1,22 @@ +import dropbox +from dotenv import load_dotenv +from pathlib import Path +import os + +load_dotenv(Path(__file__).parent / ".env") + +APP_KEY = os.getenv("DROPBOX_APP_KEY", "") +APP_SECRET = os.getenv("DROPBOX_APP_SECRET", "") +REFRESH_TOKEN = os.getenv("DROPBOX_APP_REFRESH_TOKEN", "") + +dbx = dropbox.Dropbox( + app_key=APP_KEY, + app_secret=APP_SECRET, + oauth2_refresh_token=REFRESH_TOKEN, +) + +dropbox_path = "/!!!Days/Downloads Z230/AHOJVLADO.TXT" +content = b"AHOJ VLADO" + +dbx.files_upload(content, dropbox_path, mode=dropbox.files.WriteMode.overwrite) +print(f"Nahráno: {dropbox_path}") diff --git a/EmailsImport/DockerCustomApp/BUILD.md b/EmailsImport/DockerCustomApp/BUILD.md new file mode 100644 index 0000000..cd13f1e --- /dev/null +++ b/EmailsImport/DockerCustomApp/BUILD.md @@ -0,0 +1,31 @@ +# msgreceiver — build & deploy na Unraid + +## Umístění na Unraidu +- Appdata: `/mnt/user/appdata/msgreceiver/` (síťově `\\tower\appdata\msgreceiver\`) +- Emaily: `/mnt/user/JNJEMAILS` (mount jako `/msgs` v kontejneru) + +## Kopírování souborů z Windows +Všechny soubory z `U:\janssen\EmailsImport\DockerCustomApp\` nakopírovat do `\\tower\appdata\msgreceiver\`. + +## Build & restart (SSH) +```bash +# Připojení: ssh root@192.168.1.76, heslo: 7309208104 +# Nebo přes paramiko v Pythonu (viz EmailsImport skripty) + +cd /mnt/user/appdata/msgreceiver +docker build -t msgreceiver . +docker stop msgreceiver +docker rm msgreceiver +docker run -d --name msgreceiver \ + -p 8765:8765 \ + -v /mnt/user/JNJEMAILS:/msgs \ + --restart unless-stopped \ + msgreceiver +``` + +## Kontejner +- Port: 8765 +- Restart policy: unless-stopped +- Endpointy: `/upload` (msg), `/upload-db` (db), `/upload-dropbox` (soubory do Dropboxu) +- Auth: Bearer token v app.py +- Dropbox credentials: v `.env` uvnitř image diff --git a/EmailsImport/DockerCustomApp/Dockerfile b/EmailsImport/DockerCustomApp/Dockerfile new file mode 100644 index 0000000..4c3f3f2 --- /dev/null +++ b/EmailsImport/DockerCustomApp/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.12-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install -r requirements.txt +COPY app.py . +COPY .env . +CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8765"] \ No newline at end of file diff --git a/EmailsImport/DockerCustomApp/app.py b/EmailsImport/DockerCustomApp/app.py new file mode 100644 index 0000000..37e52de --- /dev/null +++ b/EmailsImport/DockerCustomApp/app.py @@ -0,0 +1,74 @@ +from fastapi import FastAPI, UploadFile, File, Header, HTTPException +import shutil +from pathlib import Path +import os +import dropbox +from dotenv import load_dotenv + +load_dotenv(Path(__file__).parent / ".env") + +app = FastAPI() + +TOKEN = "13e1bb01-9fd5-44a8-8ce9-4ee27133d340" +SAVE_DIR = Path("/msgs") +DB_DIR = Path("/msgs/db") + +SAVE_DIR.mkdir(parents=True, exist_ok=True) +DB_DIR.mkdir(parents=True, exist_ok=True) + +DROPBOX_APP_KEY = os.getenv("DROPBOX_APP_KEY", "") +DROPBOX_APP_SECRET = os.getenv("DROPBOX_APP_SECRET", "") +DROPBOX_REFRESH_TOKEN = os.getenv("DROPBOX_APP_REFRESH_TOKEN", "") + + +@app.post("/upload") +async def upload_msg( + file: UploadFile = File(...), + authorization: str = Header(None) +): + if authorization != f"Bearer {TOKEN}": + raise HTTPException(status_code=401, detail="Unauthorized") + if not file.filename.endswith(".msg"): + raise HTTPException(status_code=400, detail="Only .msg files accepted") + dest = SAVE_DIR / file.filename + if dest.exists(): + return {"status": "exists", "file": file.filename} + with dest.open("wb") as f: + shutil.copyfileobj(file.file, f) + return {"status": "saved", "file": file.filename} + + +@app.post("/upload-db") +async def upload_db( + file: UploadFile = File(...), + authorization: str = Header(None) +): + if authorization != f"Bearer {TOKEN}": + raise HTTPException(status_code=401, detail="Unauthorized") + if not file.filename.endswith(".db"): + raise HTTPException(status_code=400, detail="Only .db files accepted") + dest = DB_DIR / file.filename + with dest.open("wb") as f: + shutil.copyfileobj(file.file, f) + return {"status": "saved", "file": file.filename} + + +@app.post("/upload-dropbox") +async def upload_dropbox( + file: UploadFile = File(...), + authorization: str = Header(None), +): + if authorization != f"Bearer {TOKEN}": + raise HTTPException(status_code=401, detail="Unauthorized") + if not DROPBOX_REFRESH_TOKEN: + raise HTTPException(status_code=500, detail="Dropbox not configured") + + content = await file.read() + dbx = dropbox.Dropbox( + app_key=DROPBOX_APP_KEY, + app_secret=DROPBOX_APP_SECRET, + oauth2_refresh_token=DROPBOX_REFRESH_TOKEN, + ) + dropbox_path = f"/!!!Days/Downloads Z230/{file.filename}" + dbx.files_upload(content, dropbox_path, mode=dropbox.files.WriteMode.overwrite) + return {"status": "uploaded", "file": file.filename, "dropbox_path": dropbox_path} diff --git a/EmailsImport/DockerCustomApp/requirements.txt b/EmailsImport/DockerCustomApp/requirements.txt new file mode 100644 index 0000000..7534feb --- /dev/null +++ b/EmailsImport/DockerCustomApp/requirements.txt @@ -0,0 +1,5 @@ +fastapi +uvicorn +python-multipart +dropbox +python-dotenv \ No newline at end of file diff --git a/EmailsImport/janssenpc_email_send.py b/EmailsImport/janssenpc_email_send.py new file mode 100644 index 0000000..cdd0b6c --- /dev/null +++ b/EmailsImport/janssenpc_email_send.py @@ -0,0 +1,174 @@ +import win32com.client +import requests +import sqlite3 +import urllib3 +from pathlib import Path +from datetime import datetime, timedelta +import tempfile +import io + +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +TOKEN = "13e1bb01-9fd5-44a8-8ce9-4ee27133d340" +UPLOAD_URL = "https://msgs.buzalka.cz/upload" +DB_PATH = r"C:\Users\vbuzalka\SQLITE\jnjemails.db" +PR_INTERNET_MESSAGE_ID = "http://schemas.microsoft.com/mapi/proptag/0x1035001E" + +def init_db(conn): + conn.execute(""" + CREATE TABLE IF NOT EXISTS messages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + message_id TEXT NOT NULL, + subject TEXT, + sender TEXT, + received_at TEXT, + folder TEXT, + source TEXT, + uploaded_at TEXT DEFAULT (datetime('now')) + ) + """) + conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS idx_message_id ON messages(message_id)") + conn.commit() + +def is_uploaded(conn, message_id): + row = conn.execute( + "SELECT 1 FROM messages WHERE message_id = ? LIMIT 1", (message_id,) + ).fetchone() + return row is not None + +def save_to_db(conn, message_id, subject, sender, received_at, folder, source): + conn.execute(""" + INSERT OR IGNORE INTO messages (message_id, subject, sender, received_at, folder, source) + VALUES (?, ?, ?, ?, ?, ?) + """, (message_id, subject, sender, received_at, folder, source)) + conn.commit() + +def upload_db(db_path): + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"jnjemails_{timestamp}.db" + with open(db_path, "rb") as f: + resp = requests.post( + "https://msgs.buzalka.cz/upload-db", + headers={"Authorization": f"Bearer {TOKEN}"}, + files={"file": (filename, f, "application/octet-stream")}, + timeout=60 + ) + print(f" DB upload: {resp.json()}") + +def upload_msg(msg_path, filename): + with open(msg_path, "rb") as f: + resp = requests.post( + UPLOAD_URL, + headers={"Authorization": f"Bearer {TOKEN}"}, + files={"file": (filename, f, "application/octet-stream")}, + timeout=30 + ) + resp.raise_for_status() + return resp.json()["status"] + +def get_folder_resume_date(conn, folder_path): + row = conn.execute( + "SELECT MAX(received_at) FROM messages WHERE folder = ?", + (folder_path,) + ).fetchone() + if not row or not row[0]: + return None + last_dt = datetime.fromisoformat(row[0]) + return last_dt - timedelta(hours=1) + +def process_folder(conn, folder, source, folder_path="", counter=None): + if counter is None: + counter = [0] + + current_path = f"{folder_path}/{folder.Name}" + + try: + resume_dt = get_folder_resume_date(conn, current_path) + + items = folder.Items + + if resume_dt: + resume_str = resume_dt.strftime("%Y/%m/%d %H:%M:%S") + filter_str = f"@SQL=\"urn:schemas:httpmail:datereceived\" > '{resume_str}'" + items = folder.Items.Restrict(filter_str) + print(f"\n Složka: {current_path} | pokračuji od: {resume_str}") + else: + print(f"\n Složka: {current_path} | od začátku") + + items.Sort("[ReceivedTime]", False) + + count = 0 + skipped = 0 + + for item in items: + try: + if not item.MessageClass.upper().startswith("IPM.NOTE"): + continue + + try: + mid = item.PropertyAccessor.GetProperty(PR_INTERNET_MESSAGE_ID) + except: + mid = None + + if not mid: + mid = f"entryid:{item.EntryID}" + + if is_uploaded(conn, mid): + skipped += 1 + continue + + with tempfile.TemporaryDirectory() as tmp: + safe_name = f"{item.EntryID[-20:]}.msg" + tmp_path = Path(tmp) / safe_name + item.SaveAs(str(tmp_path), 3) + status = upload_msg(tmp_path, safe_name) + + received = item.ReceivedTime.isoformat() if item.ReceivedTime else None + save_to_db(conn, mid, item.Subject, item.SenderEmailAddress, + received, current_path, source) + + counter[0] += 1 + count += 1 + + if counter[0] % 1000 == 0: + print(f" → celkem {counter[0]} emailů přeneseno, uploaduji DB...") + upload_db(DB_PATH) + + print(f" {status.upper():6} | {item.Subject[:60]}") + + except Exception as e: + print(f" CHYBA | {getattr(item, 'Subject', '?')[:40]} | {e}") + + print(f" → složka hotova: přeneseno {count} | skip {skipped}") + + except Exception as e: + print(f" CHYBA složka {current_path}: {e}") + + for subfolder in folder.Folders: + process_folder(conn, subfolder, source, current_path, counter) + +# --- MAIN --- +Path(DB_PATH).parent.mkdir(parents=True, exist_ok=True) +conn = sqlite3.connect(DB_PATH) +init_db(conn) + +outlook = win32com.client.Dispatch("Outlook.Application") +ns = outlook.GetNamespace("MAPI") + +for i in range(1, ns.Folders.Count + 1): + root = ns.Folders.Item(i) + +# if "Archive" in root.Name: +# print(f"\n=== {root.Name} — přeskočeno ===") +# continue + + source = "mailbox" + print(f"\n=== {root.Name} ({source}) ===") + process_folder(conn, root, source) + +# Finální DB upload po dokončení +print("\nFinální upload DB...") +upload_db(DB_PATH) + +conn.close() +print("\nHotovo.") \ No newline at end of file diff --git a/EmailsImport/janssenpc_file_send.py b/EmailsImport/janssenpc_file_send.py new file mode 100644 index 0000000..3bbdf84 --- /dev/null +++ b/EmailsImport/janssenpc_file_send.py @@ -0,0 +1,29 @@ +import requests +from pathlib import Path + +TOKEN = "13e1bb01-9fd5-44a8-8ce9-4ee27133d340" +UPLOAD_URL = "https://msgs.buzalka.cz/upload-dropbox" +SOURCE_DIR = Path(r"C:\Users\vbuzalka\OneDrive - JNJ\##JNJPrenos") + +files = [f for f in SOURCE_DIR.iterdir() if f.is_file()] + +if not files: + print("Žádné soubory k odeslání.") +else: + for f in files: + try: + with f.open("rb") as fh: + resp = requests.post( + UPLOAD_URL, + headers={"Authorization": f"Bearer {TOKEN}"}, + files={"file": (f.name, fh, "application/octet-stream")}, + timeout=120, + ) + resp.raise_for_status() + result = resp.json() + print(f" {result['status'].upper():10} | {f.name}") + f.unlink() + except Exception as e: + print(f" CHYBA | {f.name} | {e}") + +print("\nHotovo.") diff --git a/EmailsImport/janssenpc_file_watch.py b/EmailsImport/janssenpc_file_watch.py new file mode 100644 index 0000000..d945de0 --- /dev/null +++ b/EmailsImport/janssenpc_file_watch.py @@ -0,0 +1,59 @@ +import time +import requests +from pathlib import Path +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + +TOKEN = "13e1bb01-9fd5-44a8-8ce9-4ee27133d340" +UPLOAD_URL = "https://msgs.buzalka.cz/upload-dropbox" +SOURCE_DIR = Path(r"C:\Users\vbuzalka\OneDrive - JNJ\##JNJPrenos") + + +def upload_file(f: Path): + time.sleep(2) + if not f.exists() or not f.is_file(): + return + try: + with f.open("rb") as fh: + resp = requests.post( + UPLOAD_URL, + headers={"Authorization": f"Bearer {TOKEN}"}, + files={"file": (f.name, fh, "application/octet-stream")}, + timeout=120, + ) + resp.raise_for_status() + print(f" UPLOADED | {f.name}") + f.unlink() + except Exception as e: + print(f" CHYBA | {f.name} | {e}") + + +class NewFileHandler(FileSystemEventHandler): + def on_created(self, event): + if event.is_directory: + return + upload_file(Path(event.src_path)) + + def on_moved(self, event): + if event.is_directory: + return + upload_file(Path(event.dest_path)) + + +if __name__ == "__main__": + # Při startu odešli soubory, které už tam jsou + for f in SOURCE_DIR.iterdir(): + if f.is_file(): + upload_file(f) + + observer = Observer() + observer.schedule(NewFileHandler(), str(SOURCE_DIR), recursive=False) + observer.start() + print(f"Hlídám: {SOURCE_DIR}") + + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + observer.stop() + observer.join() diff --git a/Medidata/.env b/Medidata/.env index a2931ee..b800fab 100644 --- a/Medidata/.env +++ b/Medidata/.env @@ -1,3 +1,5 @@ IMEDIDATA_USERNAME=vladimir.buzalka IMEDIDATA_PASSWORD=Mar2026Ax162q8+ DOWNLOAD_DIR=./downloads + +