comparison OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp @ 4699:facea16b055b

added the "Level" argument to "/tools/bulk-content"
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 18 Jun 2021 17:58:56 +0200
parents d16c3c7f11ef
children f0038043fb97 8ffe2fdb541f
comparison
equal deleted inserted replaced
4698:d16c3c7f11ef 4699:facea16b055b
3090 3090
3091 call.GetOutput().AnswerBuffer("", MimeType_PlainText); 3091 call.GetOutput().AnswerBuffer("", MimeType_PlainText);
3092 } 3092 }
3093 3093
3094 3094
3095 static void GetBulkChildren(std::set<std::string>& target,
3096 ServerIndex& index,
3097 const std::set<std::string>& source)
3098 {
3099 target.clear();
3100
3101 for (std::set<std::string>::const_iterator
3102 it = source.begin(); it != source.end(); ++it)
3103 {
3104 std::list<std::string> children;
3105 index.GetChildren(children, *it);
3106
3107 for (std::list<std::string>::const_iterator
3108 child = children.begin(); child != children.end(); ++child)
3109 {
3110 target.insert(*child);
3111 }
3112 }
3113 }
3114
3115
3095 static void BulkContent(RestApiPostCall& call) 3116 static void BulkContent(RestApiPostCall& call)
3096 { 3117 {
3097 if (call.IsDocumentation()) 3118 if (call.IsDocumentation())
3098 { 3119 {
3099 OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human); 3120 OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
3100 3121
3101 call.GetDocumentation() 3122 call.GetDocumentation()
3102 .SetTag("System") 3123 .SetTag("System")
3103 .SetSummary("Describe a set of instances") 3124 .SetSummary("Describe a set of instances")
3104 .SetRequestField("Resources", RestApiCallDocumentation::Type_JsonListOfStrings, 3125 .SetRequestField("Resources", RestApiCallDocumentation::Type_JsonListOfStrings,
3105 "List of the Orthanc identifiers of the patients/studies/series/instances of interest.", false) 3126 "List of the Orthanc identifiers of the patients/studies/series/instances of interest.", true)
3127 .SetRequestField("Level", RestApiCallDocumentation::Type_String,
3128 "This optional argument specifies the level of interest (can be `Patient`, `Study`, `Series` or "
3129 "`Instance`). Orthanc will loop over the items inside `Resources`, and explorer upward or "
3130 "downward in the DICOM hierarchy in order to find the level of interest.", false)
3106 .SetDescription("Get the content all the DICOM patients, studies, series or instances " 3131 .SetDescription("Get the content all the DICOM patients, studies, series or instances "
3107 "whose identifiers are provided in the `Resources` field, in one single call."); 3132 "whose identifiers are provided in the `Resources` field, in one single call.");
3108 return; 3133 return;
3109 } 3134 }
3110 3135
3115 throw OrthancException(ErrorCode_BadRequest, 3140 throw OrthancException(ErrorCode_BadRequest,
3116 "The body must contain a JSON object"); 3141 "The body must contain a JSON object");
3117 } 3142 }
3118 else 3143 else
3119 { 3144 {
3145 static const char* const LEVEL = "Level";
3146
3120 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human); 3147 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human);
3121 3148
3122 ServerIndex& index = OrthancRestApi::GetIndex(call); 3149 ServerIndex& index = OrthancRestApi::GetIndex(call);
3123 3150
3124 std::list<std::string> resources;
3125 SerializationToolbox::ReadListOfStrings(resources, request, "Resources");
3126
3127 Json::Value answer = Json::arrayValue; 3151 Json::Value answer = Json::arrayValue;
3128 for (std::list<std::string>::const_iterator 3152
3129 it = resources.begin(); it != resources.end(); ++it) 3153 if (request.isMember(LEVEL))
3130 { 3154 {
3131 ResourceType type; 3155 // Complex case: Need to explore the DICOM hierarchy
3132 Json::Value item; 3156 ResourceType level = StringToResourceType(SerializationToolbox::ReadString(request, LEVEL).c_str());
3133 if (index.LookupResourceType(type, *it) && 3157
3134 index.ExpandResource(item, *it, type, format)) 3158 std::set<std::string> resources;
3135 { 3159 SerializationToolbox::ReadSetOfStrings(resources, request, "Resources");
3136 answer.append(item); 3160
3137 } 3161 std::set<std::string> interest;
3138 else 3162
3139 { 3163 assert(ResourceType_Patient < ResourceType_Study &&
3140 CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it; 3164 ResourceType_Study < ResourceType_Series &&
3165 ResourceType_Series < ResourceType_Instance);
3166
3167 for (std::set<std::string>::const_iterator
3168 it = resources.begin(); it != resources.end(); ++it)
3169 {
3170 ResourceType type;
3171 if (index.LookupResourceType(type, *it))
3172 {
3173 if (type == level)
3174 {
3175 // This resource is already from the level of interest
3176 interest.insert(*it);
3177 }
3178 else if (type < level)
3179 {
3180 // Need to explore children
3181 std::set<std::string> current;
3182 current.insert(*it);
3183
3184 for (;;)
3185 {
3186 std::set<std::string> children;
3187 GetBulkChildren(children, index, current);
3188
3189 type = GetChildResourceType(type);
3190 if (type == level)
3191 {
3192 for (std::set<std::string>::const_iterator
3193 it = children.begin(); it != children.end(); ++it)
3194 {
3195 interest.insert(*it);
3196 }
3197
3198 break; // done
3199 }
3200 else
3201 {
3202 current.swap(children);
3203 }
3204 }
3205 }
3206 else
3207 {
3208 // Need to explore parents
3209 std::string current = *it;
3210
3211 for (;;)
3212 {
3213 std::string parent;
3214 if (index.LookupParent(parent, current))
3215 {
3216 type = GetParentResourceType(type);
3217 if (type == level)
3218 {
3219 interest.insert(parent);
3220 break; // done
3221 }
3222 else
3223 {
3224 current = parent;
3225 }
3226 }
3227 else
3228 {
3229 break; // The resource has been deleted during the exploration
3230 }
3231 }
3232 }
3233 }
3234 else
3235 {
3236 CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it;
3237 }
3238 }
3239
3240 for (std::set<std::string>::const_iterator
3241 it = interest.begin(); it != interest.end(); ++it)
3242 {
3243 Json::Value item;
3244 if (index.ExpandResource(item, *it, level, format))
3245 {
3246 answer.append(item);
3247 }
3248 }
3249 }
3250 else
3251 {
3252 // Simple case: We return the queried resources as such
3253 std::list<std::string> resources;
3254 SerializationToolbox::ReadListOfStrings(resources, request, "Resources");
3255
3256 for (std::list<std::string>::const_iterator
3257 it = resources.begin(); it != resources.end(); ++it)
3258 {
3259 ResourceType type;
3260 Json::Value item;
3261 if (index.LookupResourceType(type, *it) &&
3262 index.ExpandResource(item, *it, type, format))
3263 {
3264 answer.append(item);
3265 }
3266 else
3267 {
3268 CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it;
3269 }
3141 } 3270 }
3142 } 3271 }
3143 3272
3144 call.GetOutput().AnswerJson(answer); 3273 call.GetOutput().AnswerJson(answer);
3145 } 3274 }
3152 { 3281 {
3153 call.GetDocumentation() 3282 call.GetDocumentation()
3154 .SetTag("System") 3283 .SetTag("System")
3155 .SetSummary("Delete a set of instances") 3284 .SetSummary("Delete a set of instances")
3156 .SetRequestField("Resources", RestApiCallDocumentation::Type_JsonListOfStrings, 3285 .SetRequestField("Resources", RestApiCallDocumentation::Type_JsonListOfStrings,
3157 "List of the Orthanc identifiers of the patients/studies/series/instances of interest.", false) 3286 "List of the Orthanc identifiers of the patients/studies/series/instances of interest.", true)
3158 .SetDescription("Delete all the DICOM patients, studies, series or instances " 3287 .SetDescription("Delete all the DICOM patients, studies, series or instances "
3159 "whose identifiers are provided in the `Resources` field."); 3288 "whose identifiers are provided in the `Resources` field.");
3160 return; 3289 return;
3161 } 3290 }
3162 3291