# HG changeset patch # User Sebastien Jodogne # Date 1624456949 -7200 # Node ID fb98db281d1df88752ac13e4b8304b31fd886bcc # Parent 8ffe2fdb541ff8441d1ac51b1989c6cb41209ce0 "/studies/{id}/merge" accepts instances inside its "Resources" parameter diff -r 8ffe2fdb541f -r fb98db281d1d NEWS --- 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 ----------- diff -r 8ffe2fdb541f -r fb98db281d1d OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- 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. " diff -r 8ffe2fdb541f -r fb98db281d1d OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp --- 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& 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 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); diff -r 8ffe2fdb541f -r fb98db281d1d OrthancServer/Sources/ServerJobs/MergeStudyJob.h --- 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);