changeset 4715:fb98db281d1d

"/studies/{id}/merge" accepts instances inside its "Resources" parameter
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 23 Jun 2021 16:02:29 +0200
parents 8ffe2fdb541f
children 758fe3ffb336
files NEWS OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp OrthancServer/Sources/ServerJobs/MergeStudyJob.h
diffstat 4 files changed, 57 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Jun 23 14:57:49 2021 +0200
+++ b/NEWS	Wed Jun 23 16:02:29 2021 +0200
@@ -42,6 +42,7 @@
   - GET /series/{id}/module, GET /studies/{id}/module, GET /instances/{id}/module
   - POST /tools/find
 * "/studies/{id}/split" accepts "Instances" parameter to split instances instead of series
+* "/studies/{id}/merge" accepts instances inside its "Resources" parameter
 
 Maintenance
 -----------
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Wed Jun 23 14:57:49 2021 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Wed Jun 23 16:02:29 2021 +0200
@@ -1143,11 +1143,11 @@
       call.GetDocumentation()
         .SetTag("Studies")
         .SetSummary("Merge study")
-        .SetDescription("Start a new job so as to move some DICOM series into the DICOM study whose Orthanc identifier "
+        .SetDescription("Start a new job so as to move some DICOM resources into the DICOM study whose Orthanc identifier "
                         "is provided in the URL: https://book.orthanc-server.com/users/anonymization.html#merging")
         .SetUriArgument("id", "Orthanc identifier of the study of interest")
         .SetRequestField(RESOURCES, RestApiCallDocumentation::Type_JsonListOfStrings,
-                         "The list of DICOM resources (patients, studies, series, and/or instances) to be merged "
+                         "The list of DICOM resources (studies, series, and/or instances) to be merged "
                          "into the study of interest (mandatory option)", true)
         .SetRequestField(KEEP_SOURCE, RestApiCallDocumentation::Type_Boolean,
                          "If set to `true`, instructs Orthanc to keep a copy of the original resources in their source study. "
--- a/OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp	Wed Jun 23 14:57:49 2021 +0200
+++ b/OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp	Wed Jun 23 16:02:29 2021 +0200
@@ -42,10 +42,20 @@
 
 namespace Orthanc
 {
+  static void RegisterSeries(std::map<std::string, std::string>& target,
+                             const std::string& series)
+  {
+    // Generate a target SeriesInstanceUID for this series
+    if (target.find(series) == target.end())
+    {
+      target[series] = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series);
+    }
+  }
+  
+
   void MergeStudyJob::AddSourceSeriesInternal(const std::string& series)
   {
-    // Generate a target SeriesInstanceUID for this series
-    seriesUidMap_[series] = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series);
+    RegisterSeries(seriesUidMap_, series);
 
     // Add all the instances of the series as to be processed
     std::list<std::string> instances;
@@ -240,7 +250,7 @@
   }
 
 
-  void MergeStudyJob::AddSource(const std::string& studyOrSeries)
+  void MergeStudyJob::AddSource(const std::string& publicId)
   {
     ResourceType level;
     
@@ -248,28 +258,31 @@
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
-    else if (!GetContext().GetIndex().LookupResourceType(level, studyOrSeries))
+    else if (!GetContext().GetIndex().LookupResourceType(level, publicId))
     {
       throw OrthancException(ErrorCode_UnknownResource,
-                             "Cannot find this resource: " + studyOrSeries);
+                             "Cannot find this resource: " + publicId);
     }
     else
     {
       switch (level)
       {
         case ResourceType_Study:
-          AddSourceStudyInternal(studyOrSeries);
+          AddSourceStudyInternal(publicId);
           break;
           
         case ResourceType_Series:
-          AddSourceSeries(studyOrSeries);
+          AddSourceSeries(publicId);
+          break;
+          
+        case ResourceType_Instance:
+          AddSourceInstance(publicId);
           break;
           
         default:
           throw OrthancException(ErrorCode_UnknownResource,
-                                 "This resource is neither a study, nor a series: " +
-                                 studyOrSeries + " is a " +
-                                 std::string(EnumerationToString(level)));
+                                 "This resource is neither a study, nor a series, nor an instance: " +
+                                 publicId + " is a " + std::string(EnumerationToString(level)));
       }
     }    
   }
@@ -322,6 +335,34 @@
   }
 
 
+  void MergeStudyJob::AddSourceInstance(const std::string& instance)
+  {
+    std::string parentStudy, parentSeries;
+
+    if (IsStarted())
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+    else if (!GetContext().GetIndex().LookupParent(parentSeries, instance, ResourceType_Series) ||
+             !GetContext().GetIndex().LookupParent(parentStudy, parentSeries, ResourceType_Study))
+    {
+      throw OrthancException(ErrorCode_UnknownResource,
+                             "This resource is not an instance: " + instance);
+    }
+    else if (parentStudy == targetStudy_)
+    {
+      throw OrthancException(ErrorCode_UnknownResource,
+                             "Cannot merge instance " + instance +
+                             " into its parent study " + targetStudy_);
+    }
+    else
+    {
+      RegisterSeries(seriesUidMap_, parentSeries);
+      AddInstance(instance);
+    }    
+  }
+  
+
   void MergeStudyJob::GetPublicContent(Json::Value& value)
   {
     CleaningInstancesJob::GetPublicContent(value);
--- a/OrthancServer/Sources/ServerJobs/MergeStudyJob.h	Wed Jun 23 14:57:49 2021 +0200
+++ b/OrthancServer/Sources/ServerJobs/MergeStudyJob.h	Wed Jun 23 16:02:29 2021 +0200
@@ -78,12 +78,14 @@
       return targetStudy_;
     }
 
-    void AddSource(const std::string& studyOrSeries);
+    void AddSource(const std::string& publicId);
 
     void AddSourceStudy(const std::string& study);
 
     void AddSourceSeries(const std::string& series);
 
+    void AddSourceInstance(const std::string& instance);  // New in Orthanc 1.9.4
+
     void SetOrigin(const DicomInstanceOrigin& origin);
 
     void SetOrigin(const RestApiCall& call);