From a57564ab27e3d6936f560977c5034127f6d4dae5 Mon Sep 17 00:00:00 2001
From: Florian Spreckelsen <f.spreckelsen@indiscale.com>
Date: Mon, 24 Mar 2025 12:56:50 +0100
Subject: [PATCH] FEAT(sample_upload): Allow event names in registration,
 upload, and expor

---
 .../src/ext/js/ext_samplemanagement.js            |  1 +
 .../scripting/bin/export_sample_csv.py            | 15 ++++++++++++++-
 .../bin/sample_helpers/default_constants.yml      |  1 +
 .../sample_upload_column_definitions.py           |  2 ++
 .../bin/sample_helpers/sample_upload_get_event.py | 15 +++++++++++----
 5 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/sample-management-custom/caosdb-server/caosdb-webui/src/ext/js/ext_samplemanagement.js b/sample-management-custom/caosdb-server/caosdb-webui/src/ext/js/ext_samplemanagement.js
index acf9a18..88fcefe 100644
--- a/sample-management-custom/caosdb-server/caosdb-webui/src/ext/js/ext_samplemanagement.js
+++ b/sample-management-custom/caosdb-server/caosdb-webui/src/ext/js/ext_samplemanagement.js
@@ -54,6 +54,7 @@ const ext_samplemanagement = function($, navbar, log, form_elements, form_panel,
         "Elevation start",
         "Elevation stop",
         "End date",
+        "Event name",
         "Event responsible",
         "IGSN DOI",
         "Latitude stop",
diff --git a/sample-management-custom/caosdb-server/scripting/bin/export_sample_csv.py b/sample-management-custom/caosdb-server/scripting/bin/export_sample_csv.py
index e97cdf5..7273f00 100755
--- a/sample-management-custom/caosdb-server/scripting/bin/export_sample_csv.py
+++ b/sample-management-custom/caosdb-server/scripting/bin/export_sample_csv.py
@@ -335,6 +335,17 @@ def extract_event_url(record, key):
     return None
 
 
+def extract_event_name(record, key):
+
+    events = retrieve_event(record)
+    if not events:
+        return None
+    if len(events) == 1:
+        return events[0].name
+    logger.debug(f"Sample {record.id} has multiple events.")
+    return None
+
+
 def extract_sample_name(record, key):
 
     return record.name
@@ -353,6 +364,7 @@ EXTRACTORS = use_custom_names({
     "Elevation stop": extract_ele_stop,
     "Embargo": default_find,
     "End date": extract_end_date,
+    "event_name": extract_event_name,
     "Latitude start": extract_lat_start,
     "Latitude stop": extract_lat_stop,
     "Level": extract_level,
@@ -397,7 +409,8 @@ ADDITIONAL_EXPORTS = use_custom_names([
     "LinkAhead URL",
     "parent_sample_prop",
     "Storage chain",
-    "sample_name"
+    "sample_name",
+    "event_name"
 ])
 
 
diff --git a/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/default_constants.yml b/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/default_constants.yml
index 8761cae..77791d4 100644
--- a/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/default_constants.yml
+++ b/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/default_constants.yml
@@ -26,6 +26,7 @@ csv_column_names:
   responsible_person_event: "Event responsible"
   parent_sample_prop: "Parent LinkAhead ID"
   sample_name: "Sample name"
+  event_name: "Event name"
 
 csv_column_descriptions:
   LinkAhead ID: "An ID generated by LinkAhead (either integer or URL to this entity). Do not change this column!"
diff --git a/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_column_definitions.py b/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_column_definitions.py
index 251f5f1..963470e 100644
--- a/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_column_definitions.py
+++ b/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_column_definitions.py
@@ -63,6 +63,7 @@ DATATYPE_DEFINITIONS = use_custom_names({
     "Elevation start": float,
     "Elevation stop": float,
     "End date": str,
+    "event_name": str,
     "Latitude start": float,
     "Latitude stop": float,
     "Longitude start": float,
@@ -105,6 +106,7 @@ SPECIAL_TREATMENT_SAMPLE = use_custom_names([
     "Elevation stop",
     "Embargo",
     "End date",
+    "event_name",
     "responsible_person_event",
     "igsn_doi_prop",
     "Latitude start",
diff --git a/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_get_event.py b/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_get_event.py
index b726a66..598117a 100644
--- a/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_get_event.py
+++ b/sample-management-custom/caosdb-server/scripting/bin/sample_helpers/sample_upload_get_event.py
@@ -35,6 +35,10 @@ def add_event_to_sample(sample: db.Record, data: pd.Series) -> db.Record:
     event_rt = db.get_entity_by_name(get_entity_name("event_rt"), role="RECORDTYPE")
     event = db.Record().add_parent(event_rt)
 
+    # Event name.  Replace with empty if cell is empty.
+    if get_column_header_name("event_name") in data:
+        event.name = return_value_if_not_none(data[get_column_header_name("event_name")])
+
     # We performed the sanity checks so we can assume that if the
     # Start/Stop Latitude exists, all start/stop data exist.
     positions = []
@@ -134,8 +138,11 @@ def _perform_sanity_checks(sample, data):
             )
 
     for name in ["start", "stop"]:
-        bool_list = [get_column_header_name(f"{val} {name}") in data for val in [
-            "Latitude", "Longitude", "Elevation"]]
+        bool_list = [
+            ((get_column_header_name(f"{val} {name}") in data) and
+             (return_value_if_not_none(data[get_column_header_name(f"{val} {name}")]) is not None))
+            for val in ["Latitude", "Longitude", "Elevation"]
+        ]
         raise_error = False
         if any(bool_list):
             if not all(bool_list):
@@ -155,9 +162,9 @@ def _perform_sanity_checks(sample, data):
     if (get_column_header_name("Latitude stop") in data and
             return_value_if_not_none(data[get_column_header_name("Latitude stop")]) is not None):
         if (get_column_header_name("Latitude start") not in data or
-                return_value_if_not_none(data[get_column_header_name("Latitude start")]) is not None):
+                return_value_if_not_none(data[get_column_header_name("Latitude start")]) is None):
             raise DataInconsistencyError(
-                f"Sample with {get_entity_name('entity_id')} {sample.id} has a "
+                f"Sample with {get_column_header_name('entity_id')} {sample.id} has a "
                 f"{get_entity_name('StopPosition')} but no valid "
                 f"{get_entity_name('StartPosition')}."
             )
-- 
GitLab