changeset 5122:8638522eeda1

revert changeset df4a90a65af9 that removes features used elsewhere, and protect by Force the change of UIDs
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 19 Dec 2022 15:46:33 +0100
parents 77e20ce39d6f
children ede035d48b8e
files NEWS OrthancFramework/Sources/DicomParsing/DicomModification.cpp OrthancFramework/Sources/DicomParsing/DicomModification.h OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/Sources/ServerJobs/Operations/ModifyInstanceOperation.cpp
diffstat 5 files changed, 131 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Dec 19 15:09:38 2022 +0100
+++ b/NEWS	Mon Dec 19 15:46:33 2022 +0100
@@ -14,7 +14,7 @@
 REST API
 --------
 
-* Loosen the sanity checks for DICOM modifications:
+* Loosen the sanity checks for DICOM modifications, if "Force" option is given:
   - allow modification of PatientID at study level
   - allow modification of PatientID, StudyInstanceUID at series level
   - allow modification of PatientID, StudyInstanceUID, SeriesInstanceUID at instance level
@@ -29,12 +29,6 @@
 * Tolerance for "image/jpg" MIME type instead of "image/jpeg" in /tools/create-dicom
 * /system: added MaximumStorageMode and MaximumStorageSize
 
-OrthancFramework (C++)
-----------------------
-
-* DicomModification::SetAllowManualIdentifiers() has been removed since it was always true -> code cleanup.
-
-
 Common plugins code (C++)
 -------------------------
 
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp	Mon Dec 19 15:09:38 2022 +0100
+++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp	Mon Dec 19 15:46:33 2022 +0100
@@ -522,6 +522,7 @@
   DicomModification::DicomModification() :
     removePrivateTags_(false),
     level_(ResourceType_Instance),
+    allowManualIdentifiers_(true),
     keepStudyInstanceUid_(false),
     keepSeriesInstanceUid_(false),
     keepSopInstanceUid_(false),
@@ -921,6 +922,56 @@
     }
     
 
+    // Sanity checks at the patient level
+    if (!allowManualIdentifiers_)
+    {
+      if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a patient, the StudyInstanceUID cannot be manually modified");
+      }
+
+      if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a patient, the SeriesInstanceUID cannot be manually modified");
+      }
+
+      if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a patient, the SopInstanceUID cannot be manually modified");
+      }
+    }
+
+
+    // Sanity checks at the study level
+    if (!allowManualIdentifiers_)
+    {
+      if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a study, the SeriesInstanceUID cannot be manually modified");
+      }
+
+      if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a study, the SopInstanceUID cannot be manually modified");
+      }
+    }
+
+
+    // Sanity checks at the series level
+    if (!allowManualIdentifiers_)
+    {
+      if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a series, the SopInstanceUID cannot be manually modified");
+      }
+    }
+
 
     // (0) Create a summary of the source file, if a custom generator
     // is provided
@@ -1061,6 +1112,17 @@
     }
   }
 
+  void DicomModification::SetAllowManualIdentifiers(bool check)
+  {
+    allowManualIdentifiers_ = check;
+  }
+
+  bool DicomModification::AreAllowManualIdentifiers() const
+  {
+    return allowManualIdentifiers_;
+  }
+
+
   static bool IsDatabaseKey(const DicomTag& tag)
   {
     return (tag == DICOM_TAG_PATIENT_ID ||
@@ -1213,6 +1275,62 @@
     {
       privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator");
     }
+
+    if (!force)
+    {
+      /**
+       * Sanity checks about the manual replacement of DICOM
+       * identifiers. Those checks were part of
+       * "DicomModification::Apply()" in Orthanc <= 1.11.2, and
+       * couldn't be disabled even if using the "Force" flag. Check
+       * out:
+       * https://groups.google.com/g/orthanc-users/c/xMUUZAnBa5g/m/WCEu-U2NBQAJ
+       **/
+      bool isReplacedPatientId = (IsReplaced(DICOM_TAG_PATIENT_ID) ||
+                                  uids_.find(DICOM_TAG_PATIENT_ID) != uids_.end());
+    
+      if (level_ == ResourceType_Patient && !isReplacedPatientId)
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a patient, her PatientID is required to be modified.");
+      }
+
+      if (level_ == ResourceType_Study && isReplacedPatientId)
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a study, the parent PatientID cannot be manually modified");
+      }
+
+      if (level_ == ResourceType_Series && isReplacedPatientId)
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a series, the parent PatientID cannot be manually modified");
+      }
+
+      if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a series, the parent StudyInstanceUID cannot be manually modified");
+      }
+
+      if (level_ == ResourceType_Instance && isReplacedPatientId)
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying an instance, the parent PatientID cannot be manually modified");
+      }
+      
+      if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying an instance, the parent StudyInstanceUID cannot be manually modified");
+      }
+
+      if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
+      {
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified");
+      }
+    }
   }
 
 
@@ -1282,6 +1400,7 @@
 
   static const char* REMOVE_PRIVATE_TAGS = "RemovePrivateTags";
   static const char* LEVEL = "Level";
+  static const char* ALLOW_MANUAL_IDENTIFIERS = "AllowManualIdentifiers";
   static const char* KEEP_STUDY_INSTANCE_UID = "KeepStudyInstanceUID";
   static const char* KEEP_SERIES_INSTANCE_UID = "KeepSeriesInstanceUID";
   static const char* KEEP_SOP_INSTANCE_UID = "KeepSOPInstanceUID";
@@ -1313,6 +1432,7 @@
     value = Json::objectValue;
     value[REMOVE_PRIVATE_TAGS] = removePrivateTags_;
     value[LEVEL] = EnumerationToString(level_);
+    value[ALLOW_MANUAL_IDENTIFIERS] = allowManualIdentifiers_;
     value[KEEP_STUDY_INSTANCE_UID] = keepStudyInstanceUid_;
     value[KEEP_SERIES_INSTANCE_UID] = keepSeriesInstanceUid_;
     value[KEEP_SOP_INSTANCE_UID] = keepSopInstanceUid_;
@@ -1457,6 +1577,7 @@
   {
     removePrivateTags_ = SerializationToolbox::ReadBoolean(serialized, REMOVE_PRIVATE_TAGS);
     level_ = StringToResourceType(SerializationToolbox::ReadString(serialized, LEVEL).c_str());
+    allowManualIdentifiers_ = SerializationToolbox::ReadBoolean(serialized, ALLOW_MANUAL_IDENTIFIERS);
     keepStudyInstanceUid_ = SerializationToolbox::ReadBoolean(serialized, KEEP_STUDY_INSTANCE_UID);
     keepSeriesInstanceUid_ = SerializationToolbox::ReadBoolean(serialized, KEEP_SERIES_INSTANCE_UID);
     updateReferencedRelationships_ = SerializationToolbox::ReadBoolean
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.h	Mon Dec 19 15:09:38 2022 +0100
+++ b/OrthancFramework/Sources/DicomParsing/DicomModification.h	Mon Dec 19 15:46:33 2022 +0100
@@ -133,6 +133,7 @@
     ResourceType level_;
     UidMap uidMap_;
     SetOfTags privateTagsToKeep_;
+    bool allowManualIdentifiers_;
     bool keepStudyInstanceUid_;
     bool keepSeriesInstanceUid_;
     bool keepSopInstanceUid_;
@@ -223,6 +224,10 @@
 
     void Apply(ParsedDicomFile& toModify);
 
+    void SetAllowManualIdentifiers(bool check);
+
+    bool AreAllowManualIdentifiers() const;
+
     void ParseModifyRequest(const Json::Value& request);
 
     // "patientNameOverridden" is set to "true" iff. the PatientName
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Mon Dec 19 15:09:38 2022 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Mon Dec 19 15:46:33 2022 +0100
@@ -269,6 +269,7 @@
     }
 
     DicomModification modification;
+    modification.SetAllowManualIdentifiers(true);
 
     Json::Value request;
     ParseModifyRequest(request, modification, call);
@@ -313,6 +314,7 @@
     }
 
     DicomModification modification;
+    modification.SetAllowManualIdentifiers(true);
 
     Json::Value request;
     ParseAnonymizationRequest(request, modification, call);
--- a/OrthancServer/Sources/ServerJobs/Operations/ModifyInstanceOperation.cpp	Mon Dec 19 15:09:38 2022 +0100
+++ b/OrthancServer/Sources/ServerJobs/Operations/ModifyInstanceOperation.cpp	Mon Dec 19 15:46:33 2022 +0100
@@ -43,6 +43,8 @@
       throw OrthancException(ErrorCode_NullPointer);
     }
     
+    modification_->SetAllowManualIdentifiers(true);
+
     if (modification_->IsReplaced(DICOM_TAG_PATIENT_ID))
     {
       modification_->SetLevel(ResourceType_Patient);