Mercurial > hg > orthanc
changeset 6363:43320ad053aa
edit worklists
| author | Alain Mazy <am@orthanc.team> |
|---|---|
| date | Mon, 03 Nov 2025 17:10:29 +0100 |
| parents | 37edb6be7053 |
| children | b4b7b6d39ee3 2278b9d5fb86 41152b638a4a |
| files | NEWS OrthancServer/Plugins/Samples/ModalityWorklists/Plugin.cpp |
| diffstat | 2 files changed, 111 insertions(+), 87 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Mon Nov 03 12:32:40 2025 +0100 +++ b/NEWS Mon Nov 03 17:10:29 2025 +0100 @@ -53,8 +53,10 @@ * Worklists plugin: - The Worklists plugin now provides a Rest API to: - create worklists through POST at /worklists/create - - list the worklists throuhg GET at /worklists and /worklists/{uuid} - - delete the worklists through DELETE at /worklists/{uuid} + - list the worklists throuhg GET at /worklists + - view a single worklist through GET at /worklists/{uuid} + - modify a worklist through PUT at /worklists/{uuid} + - delete a worklist through DELETE at /worklists/{uuid} All details are available in the Orthanc book: https://orthanc.uclouvain.be/book/plugins/worklists-plugin.html - New configurations: - "SaveInOrthancDatabase" to store the worklists in the Orthanc DB (provided that you are using SQLite or PostgreSQL)
--- a/OrthancServer/Plugins/Samples/ModalityWorklists/Plugin.cpp Mon Nov 03 12:32:40 2025 +0100 +++ b/OrthancServer/Plugins/Samples/ModalityWorklists/Plugin.cpp Mon Nov 03 17:10:29 2025 +0100 @@ -533,9 +533,103 @@ } - OrthancPluginErrorCode GetDeleteWorklist(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request) + void CreateOrUpdateWorklist(std::string& worklistId, + bool defaultForceValue, + OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) + { + Json::Value body; + + if (!OrthancPlugins::ReadJson(body, request->body, request->bodySize)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "A JSON payload was expected"); + } + + if (!body.isMember("Tags") || !body["Tags"].isObject()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'Tags' field is missing or not a JSON object"); + } + + bool force = defaultForceValue; + if (body.isMember("Force")) { + force = body["Force"].asBool(); + } + + Json::Value& jsonWorklist = body["Tags"]; + + if (!jsonWorklist.isMember("SpecificCharacterSet")) + { + jsonWorklist["SpecificCharacterSet"] = Orthanc::GetDicomSpecificCharacterSet(Orthanc::Encoding_Utf8); + } + + std::unique_ptr<Orthanc::ParsedDicomFile> dicom(Orthanc::ParsedDicomFile::CreateFromJson(jsonWorklist, Orthanc::DicomFromJsonFlags_None, "")); + + if (!force) + { + if (!dicom->HasTag(Orthanc::DICOM_TAG_SCHEDULED_PROCEDURE_STEP_SEQUENCE)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'Tags' is missing a 'ScheduledProcedureStepSequence'. Use 'Force': true to bypass this check."); + } + Orthanc::DicomMap step; + if (!dicom->LookupSequenceItem(step, Orthanc::DicomPath::Parse("ScheduledProcedureStepSequence"), 0) || !step.HasTag(Orthanc::DICOM_TAG_MODALITY)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'ScheduledProcedureStepSequence' is missing a 'Modality' Use 'Force': true to bypass this check."); + } + if (!dicom->LookupSequenceItem(step, Orthanc::DicomPath::Parse("ScheduledProcedureStepSequence"), 0) || !step.HasTag(Orthanc::DICOM_TAG_SCHEDULED_PROCEDURE_STEP_START_DATE)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'ScheduledProcedureStepSequence' is missing a 'ScheduledProcedureStepStartDate' Use 'Force': true to bypass this check."); + } + } + + dicom->SetIfAbsent(Orthanc::DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID, "1.2.276.0.7230010.3.1.0.1"); + + if (setStudyInstanceUidIfMissing_) + { + dicom->SetIfAbsent(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Study)); + } + + if (worklistId.empty()) + { + worklistId = Orthanc::Toolbox::GenerateUuid(); + } + + std::string dicomContent; + dicom->SaveToMemoryBuffer(dicomContent); + + switch (worklistStorage_) + { + case WorklistStorageType_Folder: + Orthanc::SystemToolbox::WriteFile(dicomContent.empty() ? NULL : dicomContent.c_str(), dicomContent.size(), + worklistDirectory_ / Orthanc::SystemToolbox::PathFromUtf8(worklistId + ".wl"), true); + break; + + case WorklistStorageType_OrthancDb: + { + Worklist wl(worklistId, dicomContent); + std::string serializedWl; + wl.Serialize(serializedWl); + + worklistsStore_->Store(worklistId, serializedWl); + break; + } + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + Json::Value response; + + response["ID"] = worklistId; + response["Path"] = "/worklists/" + worklistId; + + OrthancPlugins::AnswerJson(response, output); + } + + + OrthancPluginErrorCode GetPutDeleteWorklist(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) { std::string worklistId = std::string(request->groups[0]); @@ -555,6 +649,10 @@ OrthancPlugins::AnswerJson(jsonWl, output); } + else if (request->method == OrthancPluginHttpMethod_Put) + { + CreateOrUpdateWorklist(worklistId, true, output, url, request); + } else { OrthancPlugins::AnswerMethodNotAllowed(output, "DELETE,GET"); @@ -563,9 +661,10 @@ return OrthancPluginErrorCode_Success; } + OrthancPluginErrorCode PostCreateWorklist(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request) + const char* url, + const OrthancPluginHttpRequest* request) { if (request->method != OrthancPluginHttpMethod_Post) { @@ -573,86 +672,9 @@ } else { - Json::Value body; - - if (!OrthancPlugins::ReadJson(body, request->body, request->bodySize)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "A JSON payload was expected"); - } - - if (!body.isMember("Tags") || !body["Tags"].isObject()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'Tags' field is missing or not a JSON object"); - } - - bool force = body.isMember("Force") && body["Force"].asBool(); - - Json::Value& jsonWorklist = body["Tags"]; - - if (!jsonWorklist.isMember("SpecificCharacterSet")) - { - jsonWorklist["SpecificCharacterSet"] = Orthanc::GetDicomSpecificCharacterSet(Orthanc::Encoding_Utf8); - } - - std::unique_ptr<Orthanc::ParsedDicomFile> dicom(Orthanc::ParsedDicomFile::CreateFromJson(jsonWorklist, Orthanc::DicomFromJsonFlags_None, "")); - - if (!force) - { - if (!dicom->HasTag(Orthanc::DICOM_TAG_SCHEDULED_PROCEDURE_STEP_SEQUENCE)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'Tags' is missing a 'ScheduledProcedureStepSequence'. Use 'Force': true to bypass this check."); - } - Orthanc::DicomMap step; - if (!dicom->LookupSequenceItem(step, Orthanc::DicomPath::Parse("ScheduledProcedureStepSequence"), 0) || !step.HasTag(Orthanc::DICOM_TAG_MODALITY)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'ScheduledProcedureStepSequence' is missing a 'Modality' Use 'Force': true to bypass this check."); - } - if (!dicom->LookupSequenceItem(step, Orthanc::DicomPath::Parse("ScheduledProcedureStepSequence"), 0) || !step.HasTag(Orthanc::DICOM_TAG_SCHEDULED_PROCEDURE_STEP_START_DATE)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "'ScheduledProcedureStepSequence' is missing a 'ScheduledProcedureStepStartDate' Use 'Force': true to bypass this check."); - } - } - - dicom->SetIfAbsent(Orthanc::DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID, "1.2.276.0.7230010.3.1.0.1"); - - if (setStudyInstanceUidIfMissing_) - { - dicom->SetIfAbsent(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Study)); - } - - std::string worklistId = Orthanc::Toolbox::GenerateUuid(); - std::string dicomContent; - dicom->SaveToMemoryBuffer(dicomContent); - - switch (worklistStorage_) - { - case WorklistStorageType_Folder: - Orthanc::SystemToolbox::WriteFile(dicomContent.empty() ? NULL : dicomContent.c_str(), dicomContent.size(), - worklistDirectory_ / Orthanc::SystemToolbox::PathFromUtf8(worklistId + ".wl"), true); - break; - - case WorklistStorageType_OrthancDb: - { - Worklist wl(worklistId, dicomContent); - std::string serializedWl; - wl.Serialize(serializedWl); - - worklistsStore_->Store(worklistId, serializedWl); - break; - } - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - Json::Value response; - - response["ID"] = worklistId; - response["Path"] = "/worklists/" + worklistId; - - OrthancPlugins::AnswerJson(response, output); + std::string worklistId; + CreateOrUpdateWorklist(worklistId, false, output, url, request); } - return OrthancPluginErrorCode_Success; } @@ -794,7 +816,7 @@ OrthancPluginRegisterOnChangeCallback(OrthancPlugins::GetGlobalContext(), OnChangeCallback); OrthancPluginRegisterRestCallback(OrthancPlugins::GetGlobalContext(), "/worklists/create", PostCreateWorklist); - OrthancPluginRegisterRestCallback(OrthancPlugins::GetGlobalContext(), "/worklists/([^/]+)", GetDeleteWorklist); + OrthancPluginRegisterRestCallback(OrthancPlugins::GetGlobalContext(), "/worklists/([^/]+)", GetPutDeleteWorklist); OrthancPluginRegisterRestCallback(OrthancPlugins::GetGlobalContext(), "/worklists", ListWorklists); } else
