From cdc20457f1f05d15d90953455eccc3849dc36274 Mon Sep 17 00:00:00 2001
From: x01dc
Date: Mon, 27 Jul 2026 16:15:04 +0200
Subject: [PATCH] feat(OMNY): upload tomo PDF report to the samples web folder
Replaces the old, already-broken upload_last_pon.sh shell-out (and
assorted other dead/abandoned upload attempts left commented out in
flomni.py) with a direct HTTP upload: POSTs the just-written PDF,
base64-encoded, to omny-test.psi.ch/samples/upload.php with
filename="new.pdf" so the server assigns the number itself from its
own counter file -- the same counter newmeasurement.php
(TomoIDManager.register(), called via add_sample_database() just
before write_pdf_report()) already incremented and returned as
self.tomo_id. Runs in a background thread so a slow/unreachable host
never delays the calling tomo_scan(), and cross-checks the response
against the expected filename to flag a possible race with a
concurrent registration.
Added to TomoQueueMixin (OMNY_shared) rather than duplicated in both
LamNI and Flomni, following add_sample_database()'s existing pattern
of shared, setup-agnostic tomo-id/database logic.
---
.../bec_ipython_client/plugins/LamNI/lamni.py | 9 +--
.../plugins/OMNY_shared/tomo_queue_mixin.py | 77 +++++++++++++++++++
.../plugins/flomni/flomni.py | 14 +---
3 files changed, 83 insertions(+), 17 deletions(-)
diff --git a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py
index f2be986..576bccf 100644
--- a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py
+++ b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py
@@ -2,7 +2,6 @@ import builtins
import datetime
import json
import os
-import subprocess
import time
from pathlib import Path
@@ -2124,11 +2123,9 @@ class LamNI(TomoQueueMixin, LamNIAlignmentMixin, LamNIOpticsMixin, LamniGuiTools
file.write(
f"\nAt-each-angle hook source ('{self.at_each_angle_hook}'):\n{hook_source}"
)
- # upload_last_pon.sh no longer works and needs a rewrite -- disabled
- # for now (mirrors Flomni, which already has this commented out).
- # subprocess.run(
- # "xterm /work/sls/spec/local/XOMNY/bin/upload/upload_last_pon.sh &", shell=True
- # )
+ # Replaces the old upload_last_pon.sh script (broken, never rewritten --
+ # see git history) with a direct HTTP upload to the samples web folder.
+ self._upload_pdf_report_to_samples(user_target)
# Same tolerance as write_to_scilog(): a session without scilog/logbook
# configured (e.g. a dev/sim session) must not crash report generation
# over the logbook upload -- the PDF itself is already written above.
diff --git a/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py b/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py
index f351f5d..f91f71a 100644
--- a/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py
+++ b/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py
@@ -39,6 +39,7 @@ import builtins
import datetime
import inspect
import json
+import threading
import uuid
from typing import Callable
@@ -390,6 +391,82 @@ class TomoQueueMixin:
user=user,
)
+ # Only omny-test.psi.ch, not v1p0zyg2w9n2k9c1.myfritz.net (the host
+ # TomoIDManager.OMNY_URL registers measurements against, and the
+ # webpage generators mirror their own content to): only
+ # omny-test.psi.ch has the sample counter that actually matches
+ # self.tomo_id.
+ _SAMPLES_UPLOAD_HOSTS = ("https://omny-test.psi.ch",)
+
+ def _upload_pdf_report_to_samples(self, pdf_path: str) -> None:
+ """Upload a just-written PDF report to the OMNY samples web folder
+ (see _SAMPLES_UPLOAD_HOSTS). Identical for every setup that uses
+ ``self.tomo_id`` (set via add_sample_database() just before
+ write_pdf_report() calls this) -- shared here so LamNI/Flomni don't
+ each carry their own copy. Replaces the old, broken
+ upload_last_pon.sh script both used to shell out to.
+
+ POSTs to /samples/upload.php with filename="new.pdf" so the
+ server assigns the number itself from its own counter file
+ (countersaver.txt) -- the same counter newmeasurement.php
+ (TomoIDManager.register()) already incremented and returned as
+ self.tomo_id. Any other filename would be saved under samples/png/
+ instead of directly in samples/, per upload.php's own branching, so
+ "new.pdf" is the only way to land the PDF at samples/.pdf
+ (matching the link newmeasurement.php writes into
+ the samples listing).
+
+ Runs in a background daemon thread so a slow/unreachable host never
+ delays the calling tomo_scan().
+ """
+
+ def _run():
+ try:
+ import base64
+
+ import requests
+ import urllib3
+
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+ except ImportError:
+ print("Could not upload PDF report: 'requests' library not installed.")
+ return
+
+ try:
+ with open(pdf_path, "rb") as f:
+ filedata = base64.b64encode(f.read()).decode("ascii")
+ except OSError as exc:
+ print(f"Could not read PDF report for upload ({pdf_path}): {exc}")
+ return
+
+ expected_name = f"{self.tomo_id}.pdf"
+ for host in self._SAMPLES_UPLOAD_HOSTS:
+ url = f"{host}/samples/upload.php"
+ try:
+ r = requests.post(
+ url,
+ data={"filename": "new.pdf", "filedata": filedata},
+ timeout=20,
+ verify=False, # accept self-signed certs
+ allow_redirects=False, # SSRF hardening
+ )
+ if r.status_code != 200:
+ print(f"PDF upload to {url} -> HTTP {r.status_code}: {r.text[:120]}")
+ continue
+ if expected_name not in r.text:
+ print(
+ f"PDF upload to {url} succeeded but the server-assigned "
+ f"filename doesn't match tomo_id {self.tomo_id} (response: "
+ f"{r.text[:120]!r}) -- a concurrent measurement "
+ "registration may have raced this upload."
+ )
+ else:
+ print(f"Uploaded PDF report to {url} as {expected_name}.")
+ except Exception as exc:
+ print(f"PDF upload to {url} failed: {exc}")
+
+ threading.Thread(target=_run, name="PdfUpload", daemon=True).start()
+
# ── command-job action registry / dispatch ──────────────────────────────
def _validate_action_kwargs(self, action_name: str, kwargs: dict) -> None:
diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py
index cdd3958..bf66e7a 100644
--- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py
+++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py
@@ -3,7 +3,6 @@ import datetime
import json
import os
import random
-import subprocess
import time
from pathlib import Path
@@ -3817,16 +3816,9 @@ class Flomni(
file.write(
f"\nAt-each-angle hook source ('{self.at_each_angle_hook}'):\n{hook_source}"
)
- # subprocess.run(
- # "xterm /work/sls/spec/local/XOMNY/bin/upload/upload_last_pon.sh &", shell=True
- # )
- # status = subprocess.run(f"cp /tmp/spec-e20131-specES1.pdf {user_target}", shell=True)
- # msg = bec.tomo_progress.tomo_progressMessage()
- # logo_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "LamNI_logo.png")
- # msg.add_file(logo_path).add_text("".join(content).replace("\n", "
")).add_tag(
- # ["BEC", "tomo_parameters", f"dataset_id_{dataset_id}", "flOMNI", self.sample_name]
- # )
- # self.client.tomo_progress.send_tomo_progress_message("~/data/raw/documentation/tomo_scan_ID_{self.tomo_id}.pdf").send()
+ # Replaces the old upload_last_pon.sh script (broken, never rewritten)
+ # with a direct HTTP upload to the samples web folder.
+ self._upload_pdf_report_to_samples(user_target)
import csaxs_bec
# Ensure this is a Path object, not a string