Mercurial > hg > orthanc-authorization
changeset 338:efc9b2a319bd
Support new /tools/bulk-delete payload
| author | Alain Mazy <am@orthanc.team> |
|---|---|
| date | Fri, 17 Jul 2026 14:54:34 +0200 |
| parents | da8f5bd16407 |
| children | 0a237fbff7bb |
| files | NEWS Plugin/AuthorizationParserBase.cpp Plugin/AuthorizationParserBase.h Plugin/DefaultAuthorizationParser.cpp Plugin/Plugin.cpp |
| diffstat | 5 files changed, 117 insertions(+), 82 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Thu Apr 23 10:24:18 2026 +0200 +++ b/NEWS Fri Jul 17 14:54:34 2026 +0200 @@ -1,3 +1,8 @@ +Pending changes in the mainline +=============================== + +* Support new /tools/bulk-delete payload + 2026-04-23 - v 0.11.3 =====================
--- a/Plugin/AuthorizationParserBase.cpp Thu Apr 23 10:24:18 2026 +0200 +++ b/Plugin/AuthorizationParserBase.cpp Fri Jul 17 14:54:34 2026 +0200 @@ -38,35 +38,34 @@ } - Orthanc::ResourceType AuthorizationParserBase::AddOrthancUnknownResource(AccessedResources& target, - const std::string& orthancId) + bool AuthorizationParserBase::LookupOrthancUnknownResourceLevel(Orthanc::ResourceType& level, const std::string& orthancId) { std::string dicomId; if (resourceHierarchy_->LookupDicomUid(dicomId, Orthanc::ResourceType_Study, orthancId)) { - AddOrthancStudy(target, orthancId); - return Orthanc::ResourceType_Study; + level = Orthanc::ResourceType_Study; + return true; } if (resourceHierarchy_->LookupDicomUid(dicomId, Orthanc::ResourceType_Patient, orthancId)) { - AddOrthancPatient(target, orthancId); - return Orthanc::ResourceType_Patient; + level = Orthanc::ResourceType_Patient; + return true; } if (resourceHierarchy_->LookupDicomUid(dicomId, Orthanc::ResourceType_Series, orthancId)) { - AddOrthancSeries(target, orthancId); - return Orthanc::ResourceType_Series; + level = Orthanc::ResourceType_Series; + return true; } if (resourceHierarchy_->LookupDicomUid(dicomId, Orthanc::ResourceType_Instance, orthancId)) { - AddOrthancInstance(target, orthancId); - return Orthanc::ResourceType_Instance; + level = Orthanc::ResourceType_Instance; + return true; } - throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); + return false; } void AuthorizationParserBase::AddOrthancResource(AccessedResources& target,
--- a/Plugin/AuthorizationParserBase.h Thu Apr 23 10:24:18 2026 +0200 +++ b/Plugin/AuthorizationParserBase.h Fri Jul 17 14:54:34 2026 +0200 @@ -68,8 +68,7 @@ const std::string& instanceDicomUid); public: - Orthanc::ResourceType AddOrthancUnknownResource(AccessedResources& target, - const std::string& orthancId); + bool LookupOrthancUnknownResourceLevel(Orthanc::ResourceType& level, const std::string& orthancId); void AddOrthancResource(AccessedResources& target, Orthanc::ResourceType type,
--- a/Plugin/DefaultAuthorizationParser.cpp Thu Apr 23 10:24:18 2026 +0200 +++ b/Plugin/DefaultAuthorizationParser.cpp Fri Jul 17 14:54:34 2026 +0200 @@ -170,7 +170,11 @@ for (std::set<std::string>::const_iterator it = resourcesIds.begin(); it != resourcesIds.end(); ++it) { - AddOrthancUnknownResource(target, *it); + Orthanc::ResourceType level; + if (LookupOrthancUnknownResourceLevel(level, *it)) + { + AddOrthancResource(target, level, *it); + } } return true;
--- a/Plugin/Plugin.cpp Thu Apr 23 10:24:18 2026 +0200 +++ b/Plugin/Plugin.cpp Fri Jul 17 14:54:34 2026 +0200 @@ -94,6 +94,27 @@ } } +OrthancPluginResourceType Convert(Orthanc::ResourceType type) +{ + switch (type) + { + case Orthanc::ResourceType_Patient: + return OrthancPluginResourceType_Patient; + + case Orthanc::ResourceType_Study: + return OrthancPluginResourceType_Study; + + case Orthanc::ResourceType_Series: + return OrthancPluginResourceType_Series; + + case Orthanc::ResourceType_Instance: + return OrthancPluginResourceType_Instance; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } +} + static const char* KEY_USER_DATA = "UserData"; static const char* KEY_USER_ID = "AuditLogsUserId"; @@ -1021,8 +1042,66 @@ } } - -bool CheckHasAccessToAllResourcesInPayload(OrthancPluginRestOutput* output, const OrthancPluginHttpRequest* request) +static const char* const KEY_RESOURCES = "Resources"; +static const char* const KEY_LEVEL = "Level"; +static const char* const KEY_ID = "ID"; + +void GetResourcesList(std::map<std::string, Orthanc::ResourceType>& resources, Json::Value parsedPayload, const OrthancPluginHttpRequest* request) +{ + if (!OrthancPlugins::ReadJson(parsedPayload, request->body, request->bodySize) || !parsedPayload.isMember(KEY_RESOURCES) || !parsedPayload[KEY_RESOURCES].isArray()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "A JSON payload with a 'Resources' string array field was expected"); + } + + Orthanc::ResourceType levelInRootPayload = Orthanc::ResourceType_Instance; // random value + bool hasLevelAtRootInPayload = parsedPayload.isMember(KEY_LEVEL) && parsedPayload[KEY_LEVEL].isString(); + + if (hasLevelAtRootInPayload) + { + levelInRootPayload = Orthanc::StringToResourceType(parsedPayload[KEY_LEVEL].asString().c_str()); + } + + for (Json::ArrayIndex i = 0; i < parsedPayload[KEY_RESOURCES].size(); ++i) + { + OrthancPlugins::IAuthorizationParser::AccessedResources accessedResources; + + const Json::Value& resource = parsedPayload[KEY_RESOURCES][i]; + std::string resourceId; + + if (resource.isString()) + { + resourceId = parsedPayload[KEY_RESOURCES][i].asString(); + + if (hasLevelAtRootInPayload) + { + resources[resourceId] = levelInRootPayload; + } + else + { + Orthanc::ResourceType level; + if (authorizationParser_->LookupOrthancUnknownResourceLevel(level, resourceId)) + { + resources[resourceId] = level; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource, std::string("resource ID: ") + resourceId); + } + } + } + else if (resource.isObject() && resource.isMember(KEY_ID) && resource[KEY_ID].isString() + && resource.isMember(KEY_LEVEL) && resource[KEY_LEVEL].isString()) + { + Orthanc::ResourceType level = Orthanc::StringToResourceType(resource[KEY_LEVEL].asString().c_str()); + + resourceId = resource[KEY_ID].asString(); + resources[resourceId] = level; + } + } +} + + +bool CheckHasAccessToAllResourcesInPayload(const std::map<std::string, Orthanc::ResourceType>& resources, OrthancPluginRestOutput* output, const OrthancPluginHttpRequest* request) { // make sur the user has access to all resources listed in "Resources" (with potentialy a "Level" field to help identify the resources) @@ -1037,34 +1116,11 @@ return true; } - Json::Value payload; - if (!OrthancPlugins::ReadJson(payload, request->body, request->bodySize) || !payload.isMember("Resources") || !payload["Resources"].isArray()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "A JSON payload with a 'Resources' string array field was expected"); - } - - Orthanc::ResourceType levelInPayload = Orthanc::ResourceType_Instance; // random value - bool hasLevelInPayload = payload.isMember("Level") && payload["Level"].isString(); - - if (hasLevelInPayload) + for (std::map<std::string, Orthanc::ResourceType>::const_iterator it = resources.begin(); it != resources.end(); ++it) { - levelInPayload = Orthanc::StringToResourceType(payload["Level"].asString().c_str()); - } - - for (Json::ArrayIndex i = 0; i < payload["Resources"].size(); ++i) - { - std::string resourceId = payload["Resources"][i].asString(); - OrthancPlugins::IAuthorizationParser::AccessedResources accessedResources; - if (hasLevelInPayload) - { - authorizationParser_->AddOrthancResource(accessedResources, levelInPayload, resourceId); - } - else - { - authorizationParser_->AddOrthancUnknownResource(accessedResources, resourceId); - } + authorizationParser_->AddOrthancResource(accessedResources, it->second, it->first); bool granted = false; @@ -1075,7 +1131,7 @@ if (!granted) { - LOG(WARNING) << "Auth plugin: the user does not have access to resource " << resourceId; + LOG(WARNING) << "Auth plugin: the user does not have access to resource " << it->first; OrthancPlugins::AnswerHttpError(Orthanc::HttpStatus_403_Forbidden, output); return false; } @@ -1428,12 +1484,11 @@ } Json::Value payload; - if (!OrthancPlugins::ReadJson(payload, request->body, request->bodySize) || !payload.isMember("Resources")) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "A JSON payload was expected"); - } - - if (!CheckHasAccessToAllResourcesInPayload(output, request)) + std::map<std::string, Orthanc::ResourceType> resources; + + GetResourcesList(resources, payload, request); + + if (!CheckHasAccessToAllResourcesInPayload(resources, output, request)) { return; } @@ -1682,30 +1737,6 @@ } -OrthancPluginResourceType IdentifyResourceType(const std::string& resourceId) -{ - Json::Value v; - - if (OrthancPlugins::RestApiGet(v, "/studies/" + resourceId, false)) - { - return OrthancPluginResourceType_Study; - } - if (OrthancPlugins::RestApiGet(v, "/patients/" + resourceId, false)) - { - return OrthancPluginResourceType_Patient; - } - if (OrthancPlugins::RestApiGet(v, "/series/" + resourceId, false)) - { - return OrthancPluginResourceType_Series; - } - if (OrthancPlugins::RestApiGet(v, "/instances/" + resourceId, false)) - { - return OrthancPluginResourceType_Instance; - } - - return OrthancPluginResourceType_None; -} - void GetResourceDeletionAuditLogs(std::list<AuditLog>& auditLogs, OrthancPluginResourceType resourceType, @@ -1812,12 +1843,11 @@ } Json::Value payload; - if (!OrthancPlugins::ReadJson(payload, request->body, request->bodySize) || !payload.isMember("Resources")) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "A JSON payload was expected"); - } - - if (!CheckHasAccessToAllResourcesInPayload(output, request)) + std::map<std::string, Orthanc::ResourceType> resources; + + GetResourcesList(resources, payload, request); + + if (!CheckHasAccessToAllResourcesInPayload(resources, output, request)) { return; } @@ -1826,11 +1856,9 @@ if (enableAudiLogs) { - for (Json::ArrayIndex i = 0; i < payload["Resources"].size(); ++i) + for (std::map<std::string, Orthanc::ResourceType>::const_iterator it = resources.begin(); it != resources.end(); ++it) { - std::string resourceId = payload["Resources"][i].asString(); - OrthancPluginResourceType resourceType = IdentifyResourceType(resourceId); - GetResourceDeletionAuditLogs(auditLogs, resourceType, resourceId, request); + GetResourceDeletionAuditLogs(auditLogs, Convert(it->second), it->first, request); } }
