Mercurial > hg > orthanc
comparison OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp @ 5809:023a99146dd0 attach-custom-data tip
merged find-refactoring -> attach-custom-data
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Tue, 24 Sep 2024 12:53:43 +0200 |
parents | 8279eaab0d1d 25df40a274fd |
children |
comparison
equal
deleted
inserted
replaced
5808:63c025cf6958 | 5809:023a99146dd0 |
---|---|
20 * along with this program. If not, see <http://www.gnu.org/licenses/>. | 20 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 **/ | 21 **/ |
22 | 22 |
23 | 23 |
24 #include "../PrecompiledHeadersServer.h" | 24 #include "../PrecompiledHeadersServer.h" |
25 #include "../ResourceFinder.h" | |
26 | |
25 #include "OrthancRestApi.h" | 27 #include "OrthancRestApi.h" |
26 | 28 |
27 #include "../../../OrthancFramework/Sources/Compression/GzipCompressor.h" | 29 #include "../../../OrthancFramework/Sources/Compression/GzipCompressor.h" |
28 #include "../../../OrthancFramework/Sources/DicomFormat/DicomImageInformation.h" | 30 #include "../../../OrthancFramework/Sources/DicomFormat/DicomImageInformation.h" |
29 #include "../../../OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h" | 31 #include "../../../OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h" |
125 } | 127 } |
126 } | 128 } |
127 } | 129 } |
128 | 130 |
129 | 131 |
132 static bool ExpandResource(Json::Value& target, | |
133 ServerContext& context, | |
134 ResourceType level, | |
135 const std::string& identifier, | |
136 DicomToJsonFormat format, | |
137 bool retrieveMetadata) | |
138 { | |
139 ResourceFinder finder(level, true /* expand */); | |
140 finder.SetOrthancId(level, identifier); | |
141 finder.SetRetrieveMetadata(retrieveMetadata); | |
142 | |
143 return finder.ExecuteOneResource(target, context, format, retrieveMetadata); | |
144 } | |
145 | |
146 | |
130 // List all the patients, studies, series or instances ---------------------- | 147 // List all the patients, studies, series or instances ---------------------- |
131 | 148 |
132 static void AnswerListOfResources(RestApiOutput& output, | 149 static void AnswerListOfResources1(RestApiOutput& output, |
133 ServerContext& context, | 150 ServerContext& context, |
134 const std::list<std::string>& resources, | 151 const std::list<std::string>& resources, |
135 const std::map<std::string, std::string>& instancesIds, // optional: the id of an instance for each found resource. | 152 const std::map<std::string, std::string>& instancesIds, // optional: the id of an instance for each found resource. |
136 const std::map<std::string, boost::shared_ptr<DicomMap> >& resourcesMainDicomTags, // optional: all tags read from DB for a resource (current level and upper levels) | 153 const std::map<std::string, boost::shared_ptr<DicomMap> >& resourcesMainDicomTags, // optional: all tags read from DB for a resource (current level and upper levels) |
137 const std::map<std::string, boost::shared_ptr<Json::Value> >& resourcesDicomAsJson, // optional: the dicom-as-json for each resource | 154 const std::map<std::string, boost::shared_ptr<Json::Value> >& resourcesDicomAsJson, // optional: the dicom-as-json for each resource |
181 | 198 |
182 output.AnswerJson(answer); | 199 output.AnswerJson(answer); |
183 } | 200 } |
184 | 201 |
185 | 202 |
186 static void AnswerListOfResources(RestApiOutput& output, | 203 static void AnswerListOfResources2(RestApiOutput& output, |
187 ServerContext& context, | 204 ServerContext& context, |
188 const std::list<std::string>& resources, | 205 const std::list<std::string>& resources, |
189 ResourceType level, | 206 ResourceType level, |
190 bool expand, | 207 bool expand, |
191 DicomToJsonFormat format, | 208 DicomToJsonFormat format, |
194 { | 211 { |
195 std::map<std::string, std::string> unusedInstancesIds; | 212 std::map<std::string, std::string> unusedInstancesIds; |
196 std::map<std::string, boost::shared_ptr<DicomMap> > unusedResourcesMainDicomTags; | 213 std::map<std::string, boost::shared_ptr<DicomMap> > unusedResourcesMainDicomTags; |
197 std::map<std::string, boost::shared_ptr<Json::Value> > unusedResourcesDicomAsJson; | 214 std::map<std::string, boost::shared_ptr<Json::Value> > unusedResourcesDicomAsJson; |
198 | 215 |
199 AnswerListOfResources(output, context, resources, unusedInstancesIds, unusedResourcesMainDicomTags, unusedResourcesDicomAsJson, level, expand, format, requestedTags, allowStorageAccess); | 216 AnswerListOfResources1(output, context, resources, unusedInstancesIds, unusedResourcesMainDicomTags, unusedResourcesDicomAsJson, level, expand, format, requestedTags, allowStorageAccess); |
200 } | 217 } |
201 | 218 |
202 | 219 |
203 template <enum ResourceType resourceType> | 220 template <enum ResourceType resourceType> |
204 static void ListResources(RestApiGetCall& call) | 221 static void ListResources(RestApiGetCall& call) |
224 } | 241 } |
225 | 242 |
226 ServerIndex& index = OrthancRestApi::GetIndex(call); | 243 ServerIndex& index = OrthancRestApi::GetIndex(call); |
227 ServerContext& context = OrthancRestApi::GetContext(call); | 244 ServerContext& context = OrthancRestApi::GetContext(call); |
228 | 245 |
229 std::list<std::string> result; | 246 if (true) |
230 | 247 { |
231 std::set<DicomTag> requestedTags; | 248 /** |
232 OrthancRestApi::GetRequestedTags(requestedTags, call); | 249 * EXPERIMENTAL VERSION |
233 | 250 **/ |
234 if (call.HasArgument("limit") || | 251 |
235 call.HasArgument("since")) | 252 // TODO-FIND: include the FindRequest options parsing in a method (parse from get-arguments and from post payload) |
236 { | 253 // TODO-FIND: support other values for expand like expand=MainDicomTags,Labels,Parent,SeriesStatus |
237 if (!call.HasArgument("limit")) | 254 const bool expand = (call.HasArgument("expand") && |
238 { | 255 call.GetBooleanArgument("expand", true)); |
239 throw OrthancException(ErrorCode_BadRequest, | 256 |
240 "Missing \"limit\" argument for GET request against: " + | 257 std::set<DicomTag> requestedTags; |
241 call.FlattenUri()); | 258 OrthancRestApi::GetRequestedTags(requestedTags, call); |
242 } | 259 |
243 | 260 ResourceFinder finder(resourceType, expand); |
244 if (!call.HasArgument("since")) | 261 finder.AddRequestedTags(requestedTags); |
245 { | 262 |
246 throw OrthancException(ErrorCode_BadRequest, | 263 if (call.HasArgument("limit") || |
247 "Missing \"since\" argument for GET request against: " + | 264 call.HasArgument("since")) |
248 call.FlattenUri()); | 265 { |
249 } | 266 if (!call.HasArgument("limit")) |
250 | 267 { |
251 size_t since = boost::lexical_cast<size_t>(call.GetArgument("since", "")); | 268 throw OrthancException(ErrorCode_BadRequest, |
252 size_t limit = boost::lexical_cast<size_t>(call.GetArgument("limit", "")); | 269 "Missing \"limit\" argument for GET request against: " + |
253 index.GetAllUuids(result, resourceType, since, limit); | 270 call.FlattenUri()); |
271 } | |
272 | |
273 if (!call.HasArgument("since")) | |
274 { | |
275 throw OrthancException(ErrorCode_BadRequest, | |
276 "Missing \"since\" argument for GET request against: " + | |
277 call.FlattenUri()); | |
278 } | |
279 | |
280 uint64_t since = boost::lexical_cast<uint64_t>(call.GetArgument("since", "")); | |
281 uint64_t limit = boost::lexical_cast<uint64_t>(call.GetArgument("limit", "")); | |
282 finder.SetLimitsSince(since); | |
283 finder.SetLimitsCount(limit); | |
284 } | |
285 | |
286 Json::Value answer; | |
287 finder.Execute(answer, context, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), false /* no "Metadata" field */); | |
288 call.GetOutput().AnswerJson(answer); | |
254 } | 289 } |
255 else | 290 else |
256 { | 291 { |
257 index.GetAllUuids(result, resourceType); | 292 /** |
258 } | 293 * VERSION IN ORTHANC <= 1.12.4 |
259 | 294 **/ |
260 AnswerListOfResources(call.GetOutput(), context, result, resourceType, call.HasArgument("expand") && call.GetBooleanArgument("expand", true), | 295 |
261 OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), | 296 std::list<std::string> result; |
262 requestedTags, | 297 |
263 true /* allowStorageAccess */); | 298 std::set<DicomTag> requestedTags; |
299 OrthancRestApi::GetRequestedTags(requestedTags, call); | |
300 | |
301 if (call.HasArgument("limit") || | |
302 call.HasArgument("since")) | |
303 { | |
304 if (!call.HasArgument("limit")) | |
305 { | |
306 throw OrthancException(ErrorCode_BadRequest, | |
307 "Missing \"limit\" argument for GET request against: " + | |
308 call.FlattenUri()); | |
309 } | |
310 | |
311 if (!call.HasArgument("since")) | |
312 { | |
313 throw OrthancException(ErrorCode_BadRequest, | |
314 "Missing \"since\" argument for GET request against: " + | |
315 call.FlattenUri()); | |
316 } | |
317 | |
318 size_t since = boost::lexical_cast<size_t>(call.GetArgument("since", "")); | |
319 size_t limit = boost::lexical_cast<size_t>(call.GetArgument("limit", "")); | |
320 index.GetAllUuids(result, resourceType, since, limit); | |
321 } | |
322 else | |
323 { | |
324 index.GetAllUuids(result, resourceType); | |
325 } | |
326 | |
327 AnswerListOfResources2(call.GetOutput(), context, result, resourceType, call.HasArgument("expand") && call.GetBooleanArgument("expand", true), | |
328 OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), | |
329 requestedTags, | |
330 true /* allowStorageAccess */); | |
331 } | |
264 } | 332 } |
265 | 333 |
266 | 334 |
267 | 335 |
268 template <enum ResourceType resourceType> | 336 template <enum ResourceType resourceType> |
287 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); | 355 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); |
288 | 356 |
289 std::set<DicomTag> requestedTags; | 357 std::set<DicomTag> requestedTags; |
290 OrthancRestApi::GetRequestedTags(requestedTags, call); | 358 OrthancRestApi::GetRequestedTags(requestedTags, call); |
291 | 359 |
292 Json::Value json; | 360 if (true) |
293 if (OrthancRestApi::GetContext(call).ExpandResource( | 361 { |
294 json, call.GetUriComponent("id", ""), resourceType, format, requestedTags, true /* allowStorageAccess */)) | 362 /** |
295 { | 363 * EXPERIMENTAL VERSION |
296 call.GetOutput().AnswerJson(json); | 364 **/ |
365 | |
366 ResourceFinder finder(resourceType, true /* expand */); | |
367 finder.AddRequestedTags(requestedTags); | |
368 finder.SetOrthancId(resourceType, call.GetUriComponent("id", "")); | |
369 | |
370 Json::Value json; | |
371 if (finder.ExecuteOneResource(json, OrthancRestApi::GetContext(call), format, false /* no "Metadata" field */)) | |
372 { | |
373 call.GetOutput().AnswerJson(json); | |
374 } | |
375 } | |
376 else | |
377 { | |
378 /** | |
379 * VERSION IN ORTHANC <= 1.12.4 | |
380 **/ | |
381 | |
382 Json::Value json; | |
383 if (OrthancRestApi::GetContext(call).ExpandResource( | |
384 json, call.GetUriComponent("id", ""), resourceType, format, requestedTags, true /* allowStorageAccess */)) | |
385 { | |
386 call.GetOutput().AnswerJson(json); | |
387 } | |
297 } | 388 } |
298 } | 389 } |
299 | 390 |
300 template <enum ResourceType resourceType> | 391 template <enum ResourceType resourceType> |
301 static void DeleteSingleResource(RestApiDeleteCall& call) | 392 static void DeleteSingleResource(RestApiDeleteCall& call) |
3140 ServerContext& context, | 3231 ServerContext& context, |
3141 ResourceType level, | 3232 ResourceType level, |
3142 bool expand, | 3233 bool expand, |
3143 const std::set<DicomTag>& requestedTags) const | 3234 const std::set<DicomTag>& requestedTags) const |
3144 { | 3235 { |
3145 AnswerListOfResources(output, context, resources_, instancesIds_, resourcesMainDicomTags_, resourcesDicomAsJson_, level, expand, format_, requestedTags, IsStorageAccessAllowedForAnswers(findStorageAccessMode_)); | 3236 AnswerListOfResources1(output, context, resources_, instancesIds_, resourcesMainDicomTags_, resourcesDicomAsJson_, level, expand, format_, requestedTags, IsStorageAccessAllowedForAnswers(findStorageAccessMode_)); |
3146 } | 3237 } |
3147 }; | 3238 }; |
3148 } | 3239 } |
3149 | 3240 |
3150 | 3241 |
3252 request[KEY_LABELS_CONSTRAINT].type() != Json::stringValue) | 3343 request[KEY_LABELS_CONSTRAINT].type() != Json::stringValue) |
3253 { | 3344 { |
3254 throw OrthancException(ErrorCode_BadRequest, | 3345 throw OrthancException(ErrorCode_BadRequest, |
3255 "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be an array of strings"); | 3346 "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be an array of strings"); |
3256 } | 3347 } |
3348 else if (true) | |
3349 { | |
3350 /** | |
3351 * EXPERIMENTAL VERSION | |
3352 **/ | |
3353 | |
3354 bool expand = false; | |
3355 if (request.isMember(KEY_EXPAND)) | |
3356 { | |
3357 expand = request[KEY_EXPAND].asBool(); | |
3358 } | |
3359 | |
3360 const ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); | |
3361 | |
3362 ResourceFinder finder(level, expand); | |
3363 finder.SetDatabaseLimits(context.GetDatabaseLimits(level)); | |
3364 | |
3365 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human); | |
3366 | |
3367 if (request.isMember(KEY_LIMIT)) | |
3368 { | |
3369 int64_t tmp = request[KEY_LIMIT].asInt64(); | |
3370 if (tmp < 0) | |
3371 { | |
3372 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
3373 "Field \"" + std::string(KEY_LIMIT) + "\" must be a positive integer"); | |
3374 } | |
3375 else if (tmp != 0) // This is for compatibility with Orthanc 1.12.4 | |
3376 { | |
3377 finder.SetLimitsCount(static_cast<uint64_t>(tmp)); | |
3378 } | |
3379 } | |
3380 | |
3381 if (request.isMember(KEY_SINCE)) | |
3382 { | |
3383 int64_t tmp = request[KEY_SINCE].asInt64(); | |
3384 if (tmp < 0) | |
3385 { | |
3386 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
3387 "Field \"" + std::string(KEY_SINCE) + "\" must be a positive integer"); | |
3388 } | |
3389 else | |
3390 { | |
3391 finder.SetLimitsSince(static_cast<uint64_t>(tmp)); | |
3392 } | |
3393 } | |
3394 | |
3395 { | |
3396 bool caseSensitive = false; | |
3397 if (request.isMember(KEY_CASE_SENSITIVE)) | |
3398 { | |
3399 caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); | |
3400 } | |
3401 | |
3402 DatabaseLookup query; | |
3403 | |
3404 Json::Value::Members members = request[KEY_QUERY].getMemberNames(); | |
3405 for (size_t i = 0; i < members.size(); i++) | |
3406 { | |
3407 if (request[KEY_QUERY][members[i]].type() != Json::stringValue) | |
3408 { | |
3409 throw OrthancException(ErrorCode_BadRequest, | |
3410 "Tag \"" + members[i] + "\" must be associated with a string"); | |
3411 } | |
3412 | |
3413 const std::string value = request[KEY_QUERY][members[i]].asString(); | |
3414 | |
3415 if (!value.empty()) | |
3416 { | |
3417 // An empty string corresponds to an universal constraint, | |
3418 // so we ignore it. This mimics the behavior of class | |
3419 // "OrthancFindRequestHandler" | |
3420 query.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), | |
3421 value, caseSensitive, true); | |
3422 } | |
3423 } | |
3424 | |
3425 finder.SetDatabaseLookup(query); | |
3426 } | |
3427 | |
3428 if (request.isMember(KEY_REQUESTED_TAGS)) | |
3429 { | |
3430 std::set<DicomTag> requestedTags; | |
3431 FromDcmtkBridge::ParseListOfTags(requestedTags, request[KEY_REQUESTED_TAGS]); | |
3432 finder.AddRequestedTags(requestedTags); | |
3433 } | |
3434 | |
3435 if (request.isMember(KEY_LABELS)) // New in Orthanc 1.12.0 | |
3436 { | |
3437 for (Json::Value::ArrayIndex i = 0; i < request[KEY_LABELS].size(); i++) | |
3438 { | |
3439 if (request[KEY_LABELS][i].type() != Json::stringValue) | |
3440 { | |
3441 throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS) + "\" must contain strings"); | |
3442 } | |
3443 else | |
3444 { | |
3445 finder.AddLabel(request[KEY_LABELS][i].asString()); | |
3446 } | |
3447 } | |
3448 } | |
3449 | |
3450 finder.SetLabelsConstraint(LabelsConstraint_All); | |
3451 | |
3452 if (request.isMember(KEY_LABELS_CONSTRAINT)) | |
3453 { | |
3454 const std::string& s = request[KEY_LABELS_CONSTRAINT].asString(); | |
3455 if (s == "All") | |
3456 { | |
3457 finder.SetLabelsConstraint(LabelsConstraint_All); | |
3458 } | |
3459 else if (s == "Any") | |
3460 { | |
3461 finder.SetLabelsConstraint(LabelsConstraint_Any); | |
3462 } | |
3463 else if (s == "None") | |
3464 { | |
3465 finder.SetLabelsConstraint(LabelsConstraint_None); | |
3466 } | |
3467 else | |
3468 { | |
3469 throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be \"All\", \"Any\", or \"None\""); | |
3470 } | |
3471 } | |
3472 | |
3473 Json::Value answer; | |
3474 finder.Execute(answer, context, format, false /* no "Metadata" field */); | |
3475 call.GetOutput().AnswerJson(answer); | |
3476 } | |
3257 else | 3477 else |
3258 { | 3478 { |
3479 /** | |
3480 * VERSION IN ORTHANC <= 1.12.4 | |
3481 **/ | |
3259 bool expand = false; | 3482 bool expand = false; |
3260 if (request.isMember(KEY_EXPAND)) | 3483 if (request.isMember(KEY_EXPAND)) |
3261 { | 3484 { |
3262 expand = request[KEY_EXPAND].asBool(); | 3485 expand = request[KEY_EXPAND].asBool(); |
3263 } | 3486 } |
3398 } | 3621 } |
3399 | 3622 |
3400 ServerIndex& index = OrthancRestApi::GetIndex(call); | 3623 ServerIndex& index = OrthancRestApi::GetIndex(call); |
3401 ServerContext& context = OrthancRestApi::GetContext(call); | 3624 ServerContext& context = OrthancRestApi::GetContext(call); |
3402 | 3625 |
3626 const bool expand = (!call.HasArgument("expand") || | |
3627 // this "expand" is the only one to have a false default value to keep backward compatibility | |
3628 call.GetBooleanArgument("expand", false)); | |
3629 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); | |
3630 | |
3403 std::set<DicomTag> requestedTags; | 3631 std::set<DicomTag> requestedTags; |
3404 OrthancRestApi::GetRequestedTags(requestedTags, call); | 3632 OrthancRestApi::GetRequestedTags(requestedTags, call); |
3405 | 3633 |
3406 std::list<std::string> a, b, c; | 3634 if (true) |
3407 a.push_back(call.GetUriComponent("id", "")); | 3635 { |
3408 | 3636 /** |
3409 ResourceType type = start; | 3637 * EXPERIMENTAL VERSION |
3410 while (type != end) | 3638 **/ |
3411 { | 3639 |
3412 b.clear(); | 3640 ResourceFinder finder(end, expand); |
3413 | 3641 finder.SetOrthancId(start, call.GetUriComponent("id", "")); |
3414 for (std::list<std::string>::const_iterator | 3642 finder.AddRequestedTags(requestedTags); |
3415 it = a.begin(); it != a.end(); ++it) | 3643 |
3416 { | 3644 Json::Value answer; |
3417 index.GetChildren(c, *it); | 3645 finder.Execute(answer, context, format, false /* no "Metadata" field */); |
3418 b.splice(b.begin(), c); | 3646 call.GetOutput().AnswerJson(answer); |
3419 } | 3647 } |
3420 | 3648 else |
3421 type = GetChildResourceType(type); | 3649 { |
3422 | 3650 /** |
3423 a.clear(); | 3651 * VERSION IN ORTHANC <= 1.12.4 |
3424 a.splice(a.begin(), b); | 3652 **/ |
3425 } | 3653 std::list<std::string> a, b, c; |
3426 | 3654 a.push_back(call.GetUriComponent("id", "")); |
3427 AnswerListOfResources(call.GetOutput(), context, a, type, !call.HasArgument("expand") || call.GetBooleanArgument("expand", false), // this "expand" is the only one to have a false default value to keep backward compatibility | 3655 |
3428 OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), | 3656 ResourceType type = start; |
3429 requestedTags, | 3657 while (type != end) |
3430 true /* allowStorageAccess */); | 3658 { |
3659 b.clear(); | |
3660 | |
3661 for (std::list<std::string>::const_iterator | |
3662 it = a.begin(); it != a.end(); ++it) | |
3663 { | |
3664 index.GetChildren(c, *it); | |
3665 b.splice(b.begin(), c); | |
3666 } | |
3667 | |
3668 type = GetChildResourceType(type); | |
3669 | |
3670 a.clear(); | |
3671 a.splice(a.begin(), b); | |
3672 } | |
3673 | |
3674 AnswerListOfResources2(call.GetOutput(), context, a, type, expand, format, requestedTags, true /* allowStorageAccess */); | |
3675 } | |
3431 } | 3676 } |
3432 | 3677 |
3433 | 3678 |
3434 static void GetChildInstancesTags(RestApiGetCall& call) | 3679 static void GetChildInstancesTags(RestApiGetCall& call) |
3435 { | 3680 { |
3538 assert(currentType == end); | 3783 assert(currentType == end); |
3539 | 3784 |
3540 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); | 3785 const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); |
3541 | 3786 |
3542 Json::Value resource; | 3787 Json::Value resource; |
3543 if (OrthancRestApi::GetContext(call).ExpandResource(resource, current, end, format, requestedTags, true /* allowStorageAccess */)) | 3788 |
3544 { | 3789 if (true) |
3545 call.GetOutput().AnswerJson(resource); | 3790 { |
3791 /** | |
3792 * EXPERIMENTAL VERSION | |
3793 **/ | |
3794 if (ExpandResource(resource, OrthancRestApi::GetContext(call), currentType, current, format, false)) | |
3795 { | |
3796 call.GetOutput().AnswerJson(resource); | |
3797 } | |
3798 } | |
3799 else | |
3800 { | |
3801 /** | |
3802 * VERSION IN ORTHANC <= 1.12.4 | |
3803 **/ | |
3804 if (OrthancRestApi::GetContext(call).ExpandResource(resource, current, end, format, requestedTags, true /* allowStorageAccess */)) | |
3805 { | |
3806 call.GetOutput().AnswerJson(resource); | |
3807 } | |
3546 } | 3808 } |
3547 } | 3809 } |
3548 | 3810 |
3549 | 3811 |
3550 static void ExtractPdf(RestApiGetCall& call) | 3812 static void ExtractPdf(RestApiGetCall& call) |
3971 } | 4233 } |
3972 | 4234 |
3973 for (std::set<std::string>::const_iterator | 4235 for (std::set<std::string>::const_iterator |
3974 it = interest.begin(); it != interest.end(); ++it) | 4236 it = interest.begin(); it != interest.end(); ++it) |
3975 { | 4237 { |
3976 Json::Value item; | 4238 if (true) |
3977 std::set<DicomTag> emptyRequestedTags; // not supported for bulk content | |
3978 | |
3979 if (OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) | |
3980 { | 4239 { |
3981 if (metadata) | 4240 /** |
4241 * EXPERIMENTAL VERSION | |
4242 **/ | |
4243 Json::Value item; | |
4244 if (ExpandResource(item, OrthancRestApi::GetContext(call), level, *it, format, metadata)) | |
3982 { | 4245 { |
3983 AddMetadata(item[METADATA], index, *it, level); | 4246 answer.append(item); |
3984 } | 4247 } |
3985 | 4248 } |
3986 answer.append(item); | 4249 else |
4250 { | |
4251 /** | |
4252 * VERSION IN ORTHANC <= 1.12.4 | |
4253 **/ | |
4254 Json::Value item; | |
4255 std::set<DicomTag> emptyRequestedTags; // not supported for bulk content | |
4256 | |
4257 if (OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) | |
4258 { | |
4259 if (metadata) | |
4260 { | |
4261 AddMetadata(item[METADATA], index, *it, level); | |
4262 } | |
4263 | |
4264 answer.append(item); | |
4265 } | |
3987 } | 4266 } |
3988 } | 4267 } |
3989 } | 4268 } |
3990 else | 4269 else |
3991 { | 4270 { |
3998 { | 4277 { |
3999 ResourceType level; | 4278 ResourceType level; |
4000 Json::Value item; | 4279 Json::Value item; |
4001 std::set<DicomTag> emptyRequestedTags; // not supported for bulk content | 4280 std::set<DicomTag> emptyRequestedTags; // not supported for bulk content |
4002 | 4281 |
4003 if (index.LookupResourceType(level, *it) && | 4282 if (true) |
4004 OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) | |
4005 { | 4283 { |
4006 if (metadata) | 4284 /** |
4285 * EXPERIMENTAL VERSION | |
4286 **/ | |
4287 if (index.LookupResourceType(level, *it) && | |
4288 ExpandResource(item, OrthancRestApi::GetContext(call), level, *it, format, metadata)) | |
4007 { | 4289 { |
4008 AddMetadata(item[METADATA], index, *it, level); | 4290 answer.append(item); |
4009 } | 4291 } |
4010 | |
4011 answer.append(item); | |
4012 } | 4292 } |
4013 else | 4293 else |
4014 { | 4294 { |
4015 CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it; | 4295 /** |
4296 * VERSION IN ORTHANC <= 1.12.4 | |
4297 **/ | |
4298 if (index.LookupResourceType(level, *it) && | |
4299 OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) | |
4300 { | |
4301 if (metadata) | |
4302 { | |
4303 AddMetadata(item[METADATA], index, *it, level); | |
4304 } | |
4305 | |
4306 answer.append(item); | |
4307 } | |
4308 else | |
4309 { | |
4310 CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it; | |
4311 } | |
4016 } | 4312 } |
4017 } | 4313 } |
4018 } | 4314 } |
4019 | 4315 |
4020 call.GetOutput().AnswerJson(answer); | 4316 call.GetOutput().AnswerJson(answer); |
4073 Register("/instances", ListResources<ResourceType_Instance>); | 4369 Register("/instances", ListResources<ResourceType_Instance>); |
4074 Register("/patients", ListResources<ResourceType_Patient>); | 4370 Register("/patients", ListResources<ResourceType_Patient>); |
4075 Register("/series", ListResources<ResourceType_Series>); | 4371 Register("/series", ListResources<ResourceType_Series>); |
4076 Register("/studies", ListResources<ResourceType_Study>); | 4372 Register("/studies", ListResources<ResourceType_Study>); |
4077 | 4373 |
4078 Register("/instances/{id}", DeleteSingleResource<ResourceType_Instance>); | 4374 if (!context_.IsReadOnly()) |
4375 { | |
4376 Register("/instances/{id}", DeleteSingleResource<ResourceType_Instance>); | |
4377 Register("/patients/{id}", DeleteSingleResource<ResourceType_Patient>); | |
4378 Register("/series/{id}", DeleteSingleResource<ResourceType_Series>); | |
4379 Register("/studies/{id}", DeleteSingleResource<ResourceType_Study>); | |
4380 | |
4381 Register("/tools/bulk-delete", BulkDelete); | |
4382 } | |
4383 else | |
4384 { | |
4385 LOG(WARNING) << "READ-ONLY SYSTEM: DELETE routes are not available"; | |
4386 } | |
4387 | |
4079 Register("/instances/{id}", GetSingleResource<ResourceType_Instance>); | 4388 Register("/instances/{id}", GetSingleResource<ResourceType_Instance>); |
4080 Register("/patients/{id}", DeleteSingleResource<ResourceType_Patient>); | |
4081 Register("/patients/{id}", GetSingleResource<ResourceType_Patient>); | 4389 Register("/patients/{id}", GetSingleResource<ResourceType_Patient>); |
4082 Register("/series/{id}", DeleteSingleResource<ResourceType_Series>); | |
4083 Register("/series/{id}", GetSingleResource<ResourceType_Series>); | 4390 Register("/series/{id}", GetSingleResource<ResourceType_Series>); |
4084 Register("/studies/{id}", DeleteSingleResource<ResourceType_Study>); | |
4085 Register("/studies/{id}", GetSingleResource<ResourceType_Study>); | 4391 Register("/studies/{id}", GetSingleResource<ResourceType_Study>); |
4086 | 4392 |
4087 Register("/instances/{id}/statistics", GetResourceStatistics); | 4393 Register("/instances/{id}/statistics", GetResourceStatistics); |
4088 Register("/patients/{id}/statistics", GetResourceStatistics); | 4394 Register("/patients/{id}/statistics", GetResourceStatistics); |
4089 Register("/studies/{id}/statistics", GetResourceStatistics); | 4395 Register("/studies/{id}/statistics", GetResourceStatistics); |
4124 Register("/instances/{id}/matlab", GetMatlabImage); | 4430 Register("/instances/{id}/matlab", GetMatlabImage); |
4125 Register("/instances/{id}/header", GetInstanceHeader); | 4431 Register("/instances/{id}/header", GetInstanceHeader); |
4126 Register("/instances/{id}/numpy", GetNumpyInstance); // New in Orthanc 1.10.0 | 4432 Register("/instances/{id}/numpy", GetNumpyInstance); // New in Orthanc 1.10.0 |
4127 | 4433 |
4128 Register("/patients/{id}/protected", IsProtectedPatient); | 4434 Register("/patients/{id}/protected", IsProtectedPatient); |
4129 Register("/patients/{id}/protected", SetPatientProtection); | 4435 |
4436 if (!context_.IsReadOnly()) | |
4437 { | |
4438 Register("/patients/{id}/protected", SetPatientProtection); | |
4439 } | |
4440 else | |
4441 { | |
4442 LOG(WARNING) << "READ-ONLY SYSTEM: PUT /patients/{id}/protected route is not available"; | |
4443 } | |
4444 | |
4130 | 4445 |
4131 std::vector<std::string> resourceTypes; | 4446 std::vector<std::string> resourceTypes; |
4132 resourceTypes.push_back("patients"); | 4447 resourceTypes.push_back("patients"); |
4133 resourceTypes.push_back("studies"); | 4448 resourceTypes.push_back("studies"); |
4134 resourceTypes.push_back("series"); | 4449 resourceTypes.push_back("series"); |
4142 Register("/" + resourceTypes[i] + "/{id}/metadata/{name}", SetMetadata); | 4457 Register("/" + resourceTypes[i] + "/{id}/metadata/{name}", SetMetadata); |
4143 | 4458 |
4144 // New in Orthanc 1.12.0 | 4459 // New in Orthanc 1.12.0 |
4145 Register("/" + resourceTypes[i] + "/{id}/labels", ListLabels); | 4460 Register("/" + resourceTypes[i] + "/{id}/labels", ListLabels); |
4146 Register("/" + resourceTypes[i] + "/{id}/labels/{label}", GetLabel); | 4461 Register("/" + resourceTypes[i] + "/{id}/labels/{label}", GetLabel); |
4147 Register("/" + resourceTypes[i] + "/{id}/labels/{label}", RemoveLabel); | 4462 |
4148 Register("/" + resourceTypes[i] + "/{id}/labels/{label}", AddLabel); | 4463 if (!context_.IsReadOnly()) |
4464 { | |
4465 Register("/" + resourceTypes[i] + "/{id}/labels/{label}", RemoveLabel); | |
4466 Register("/" + resourceTypes[i] + "/{id}/labels/{label}", AddLabel); | |
4467 } | |
4149 | 4468 |
4150 Register("/" + resourceTypes[i] + "/{id}/attachments", ListAttachments); | 4469 Register("/" + resourceTypes[i] + "/{id}/attachments", ListAttachments); |
4151 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}", DeleteAttachment); | |
4152 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}", GetAttachmentOperations); | 4470 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}", GetAttachmentOperations); |
4153 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}", UploadAttachment); | |
4154 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compress", ChangeAttachmentCompression<CompressionType_ZlibWithSize>); | |
4155 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compressed-data", GetAttachmentData<0>); | 4471 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compressed-data", GetAttachmentData<0>); |
4156 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compressed-md5", GetAttachmentCompressedMD5); | 4472 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compressed-md5", GetAttachmentCompressedMD5); |
4157 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compressed-size", GetAttachmentCompressedSize); | 4473 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compressed-size", GetAttachmentCompressedSize); |
4158 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/data", GetAttachmentData<1>); | 4474 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/data", GetAttachmentData<1>); |
4159 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/is-compressed", IsAttachmentCompressed); | 4475 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/is-compressed", IsAttachmentCompressed); |
4160 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/md5", GetAttachmentMD5); | 4476 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/md5", GetAttachmentMD5); |
4161 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/size", GetAttachmentSize); | 4477 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/size", GetAttachmentSize); |
4162 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/uncompress", ChangeAttachmentCompression<CompressionType_None>); | |
4163 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/info", GetAttachmentInfo); | 4478 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/info", GetAttachmentInfo); |
4164 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/verify-md5", VerifyAttachment); | 4479 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/verify-md5", VerifyAttachment); |
4165 } | 4480 |
4166 | 4481 if (!context_.IsReadOnly()) |
4167 Register("/tools/invalidate-tags", InvalidateTags); | 4482 { |
4483 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}", DeleteAttachment); | |
4484 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}", UploadAttachment); | |
4485 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/compress", ChangeAttachmentCompression<CompressionType_ZlibWithSize>); | |
4486 Register("/" + resourceTypes[i] + "/{id}/attachments/{name}/uncompress", ChangeAttachmentCompression<CompressionType_None>); | |
4487 } | |
4488 } | |
4489 | |
4490 if (context_.IsReadOnly()) | |
4491 { | |
4492 LOG(WARNING) << "READ-ONLY SYSTEM: deactivating PUT, POST and DELETE attachments routes"; | |
4493 LOG(WARNING) << "READ-ONLY SYSTEM: deactivating PUT and DELETE labels routes"; | |
4494 } | |
4495 | |
4496 if (!context_.IsReadOnly()) | |
4497 { | |
4498 Register("/tools/invalidate-tags", InvalidateTags); | |
4499 } | |
4500 | |
4168 Register("/tools/lookup", Lookup); | 4501 Register("/tools/lookup", Lookup); |
4169 Register("/tools/find", Find); | 4502 Register("/tools/find", Find); |
4170 | 4503 |
4171 Register("/patients/{id}/studies", GetChildResources<ResourceType_Patient, ResourceType_Study>); | 4504 Register("/patients/{id}/studies", GetChildResources<ResourceType_Patient, ResourceType_Study>); |
4172 Register("/patients/{id}/series", GetChildResources<ResourceType_Patient, ResourceType_Series>); | 4505 Register("/patients/{id}/series", GetChildResources<ResourceType_Patient, ResourceType_Series>); |
4189 Register("/instances/{id}/content/*", GetRawContent); | 4522 Register("/instances/{id}/content/*", GetRawContent); |
4190 | 4523 |
4191 Register("/series/{id}/ordered-slices", OrderSlices); | 4524 Register("/series/{id}/ordered-slices", OrderSlices); |
4192 Register("/series/{id}/numpy", GetNumpySeries); // New in Orthanc 1.10.0 | 4525 Register("/series/{id}/numpy", GetNumpySeries); // New in Orthanc 1.10.0 |
4193 | 4526 |
4194 Register("/patients/{id}/reconstruct", ReconstructResource<ResourceType_Patient>); | 4527 if (!context_.IsReadOnly()) |
4195 Register("/studies/{id}/reconstruct", ReconstructResource<ResourceType_Study>); | 4528 { |
4196 Register("/series/{id}/reconstruct", ReconstructResource<ResourceType_Series>); | 4529 Register("/patients/{id}/reconstruct", ReconstructResource<ResourceType_Patient>); |
4197 Register("/instances/{id}/reconstruct", ReconstructResource<ResourceType_Instance>); | 4530 Register("/studies/{id}/reconstruct", ReconstructResource<ResourceType_Study>); |
4198 Register("/tools/reconstruct", ReconstructAllResources); | 4531 Register("/series/{id}/reconstruct", ReconstructResource<ResourceType_Series>); |
4532 Register("/instances/{id}/reconstruct", ReconstructResource<ResourceType_Instance>); | |
4533 Register("/tools/reconstruct", ReconstructAllResources); | |
4534 } | |
4535 else | |
4536 { | |
4537 LOG(WARNING) << "READ-ONLY SYSTEM: deactivating /reconstruct routes"; | |
4538 } | |
4199 | 4539 |
4200 Register("/tools/bulk-content", BulkContent); | 4540 Register("/tools/bulk-content", BulkContent); |
4201 Register("/tools/bulk-delete", BulkDelete); | 4541 } |
4202 } | |
4203 } | 4542 } |