Mercurial > hg > orthanc
comparison OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp @ 4693:45bce660ce3a
added routes for bulk anonymization/modification
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 16 Jun 2021 16:44:04 +0200 |
parents | fcd2dc7c8f31 |
children | da1edb7d6332 |
comparison
equal
deleted
inserted
replaced
4692:e68edf92e5cc | 4693:45bce660ce3a |
---|---|
144 } | 144 } |
145 | 145 |
146 if (call.ParseJsonRequest(request) && | 146 if (call.ParseJsonRequest(request) && |
147 request.isObject()) | 147 request.isObject()) |
148 { | 148 { |
149 bool patientNameReplaced; | 149 bool patientNameOverridden; |
150 target.ParseAnonymizationRequest(patientNameReplaced, request); | 150 target.ParseAnonymizationRequest(patientNameOverridden, request); |
151 | 151 |
152 if (patientNameReplaced) | 152 if (!patientNameOverridden) |
153 { | 153 { |
154 // Overwrite the random Patient's Name by one that is more | 154 // Override the random Patient's Name by one that is more |
155 // user-friendly (provided none was specified by the user) | 155 // user-friendly (provided none was specified by the user) |
156 target.Replace(DICOM_TAG_PATIENT_NAME, GeneratePatientName(OrthancRestApi::GetContext(call)), true); | 156 target.Replace(DICOM_TAG_PATIENT_NAME, GeneratePatientName(OrthancRestApi::GetContext(call)), true); |
157 } | 157 } |
158 } | 158 } |
159 else | 159 else |
203 } | 203 } |
204 } | 204 } |
205 else | 205 else |
206 { | 206 { |
207 modified->Answer(call.GetOutput()); | 207 modified->Answer(call.GetOutput()); |
208 } | |
209 } | |
210 | |
211 | |
212 static ResourceType DetectModifyLevel(const DicomModification& modification) | |
213 { | |
214 if (modification.IsReplaced(DICOM_TAG_PATIENT_ID)) | |
215 { | |
216 return ResourceType_Patient; | |
217 } | |
218 else if (modification.IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) | |
219 { | |
220 return ResourceType_Study; | |
221 } | |
222 else if (modification.IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) | |
223 { | |
224 return ResourceType_Series; | |
225 } | |
226 else | |
227 { | |
228 return ResourceType_Instance; | |
208 } | 229 } |
209 } | 230 } |
210 | 231 |
211 | 232 |
212 static void ModifyInstance(RestApiPostCall& call) | 233 static void ModifyInstance(RestApiPostCall& call) |
228 modification.SetAllowManualIdentifiers(true); | 249 modification.SetAllowManualIdentifiers(true); |
229 | 250 |
230 Json::Value request; | 251 Json::Value request; |
231 ParseModifyRequest(request, modification, call); | 252 ParseModifyRequest(request, modification, call); |
232 | 253 |
233 if (modification.IsReplaced(DICOM_TAG_PATIENT_ID)) | 254 modification.SetLevel(DetectModifyLevel(modification)); |
234 { | |
235 modification.SetLevel(ResourceType_Patient); | |
236 } | |
237 else if (modification.IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) | |
238 { | |
239 modification.SetLevel(ResourceType_Study); | |
240 } | |
241 else if (modification.IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) | |
242 { | |
243 modification.SetLevel(ResourceType_Series); | |
244 } | |
245 else | |
246 { | |
247 modification.SetLevel(ResourceType_Instance); | |
248 } | |
249 | 255 |
250 static const char* TRANSCODE = "Transcode"; | 256 static const char* TRANSCODE = "Transcode"; |
251 if (request.isMember(TRANSCODE)) | 257 if (request.isMember(TRANSCODE)) |
252 { | 258 { |
253 std::string s = SerializationToolbox::ReadString(request, TRANSCODE); | 259 std::string s = SerializationToolbox::ReadString(request, TRANSCODE); |
309 | 315 |
310 static void SubmitModificationJob(std::unique_ptr<DicomModification>& modification, | 316 static void SubmitModificationJob(std::unique_ptr<DicomModification>& modification, |
311 bool isAnonymization, | 317 bool isAnonymization, |
312 RestApiPostCall& call, | 318 RestApiPostCall& call, |
313 const Json::Value& body, | 319 const Json::Value& body, |
314 ResourceType level) | 320 ResourceType outputLevel /* unused for multiple resources */, |
321 bool isSingleResource, | |
322 const std::set<std::string>& resources) | |
315 { | 323 { |
316 ServerContext& context = OrthancRestApi::GetContext(call); | 324 ServerContext& context = OrthancRestApi::GetContext(call); |
317 | 325 |
318 std::unique_ptr<ResourceModificationJob> job(new ResourceModificationJob(context)); | 326 std::unique_ptr<ResourceModificationJob> job(new ResourceModificationJob(context)); |
319 | 327 |
320 job->SetModification(modification.release(), level, isAnonymization); | 328 if (isSingleResource) // This notably configures the output format |
329 { | |
330 job->SetSingleResourceModification(modification.release(), outputLevel, isAnonymization); | |
331 } | |
332 else | |
333 { | |
334 job->SetMultipleResourcesModification(modification.release(), isAnonymization); | |
335 } | |
336 | |
321 job->SetOrigin(call); | 337 job->SetOrigin(call); |
322 SetKeepSource(*job, body); | 338 SetKeepSource(*job, body); |
323 | 339 |
324 static const char* TRANSCODE = "Transcode"; | 340 static const char* TRANSCODE = "Transcode"; |
325 if (body.isMember(TRANSCODE)) | 341 if (body.isMember(TRANSCODE)) |
326 { | 342 { |
327 job->SetTranscode(SerializationToolbox::ReadString(body, TRANSCODE)); | 343 job->SetTranscode(SerializationToolbox::ReadString(body, TRANSCODE)); |
328 } | 344 } |
345 | |
346 for (std::set<std::string>::const_iterator | |
347 it = resources.begin(); it != resources.end(); ++it) | |
348 { | |
349 context.AddChildInstances(*job, *it); | |
350 } | |
329 | 351 |
330 context.AddChildInstances(*job, call.GetUriComponent("id", "")); | |
331 job->AddTrailingStep(); | 352 job->AddTrailingStep(); |
332 | 353 |
333 OrthancRestApi::GetApi(call).SubmitCommandsJob | 354 OrthancRestApi::GetApi(call).SubmitCommandsJob |
334 (call, job.release(), true /* synchronous by default */, body); | 355 (call, job.release(), true /* synchronous by default */, body); |
356 } | |
357 | |
358 | |
359 static void SubmitModificationJob(std::unique_ptr<DicomModification>& modification, | |
360 bool isAnonymization, | |
361 RestApiPostCall& call, | |
362 const Json::Value& body, | |
363 ResourceType outputLevel) | |
364 { | |
365 // This was the only flavor in Orthanc <= 1.9.3 | |
366 std::set<std::string> resources; | |
367 resources.insert(call.GetUriComponent("id", "")); | |
368 | |
369 SubmitModificationJob(modification, isAnonymization, call, body, outputLevel, | |
370 true /* single resource */, resources); | |
371 } | |
372 | |
373 | |
374 static void SubmitBulkJob(std::unique_ptr<DicomModification>& modification, | |
375 bool isAnonymization, | |
376 RestApiPostCall& call, | |
377 const Json::Value& body) | |
378 { | |
379 std::set<std::string> resources; | |
380 SerializationToolbox::ReadSetOfStrings(resources, body, "Resources"); | |
381 | |
382 SubmitModificationJob(modification, isAnonymization, | |
383 call, body, ResourceType_Instance /* arbitrary value, unused */, | |
384 false /* multiple resources */, resources); | |
335 } | 385 } |
336 | 386 |
337 | 387 |
338 template <enum ResourceType resourceType> | 388 template <enum ResourceType resourceType> |
339 static void ModifyResource(RestApiPostCall& call) | 389 static void ModifyResource(RestApiPostCall& call) |
358 | 408 |
359 Json::Value body; | 409 Json::Value body; |
360 ParseModifyRequest(body, *modification, call); | 410 ParseModifyRequest(body, *modification, call); |
361 | 411 |
362 modification->SetLevel(resourceType); | 412 modification->SetLevel(resourceType); |
363 | 413 |
364 SubmitModificationJob(modification, false /* not an anonymization */, | 414 SubmitModificationJob(modification, false /* not an anonymization */, |
365 call, body, resourceType); | 415 call, body, resourceType); |
416 } | |
417 | |
418 | |
419 // New in Orthanc 1.9.4 | |
420 static void BulkModify(RestApiPostCall& call) | |
421 { | |
422 if (call.IsDocumentation()) | |
423 { | |
424 OrthancRestApi::DocumentSubmitCommandsJob(call); | |
425 DocumentModifyOptions(call); | |
426 call.GetDocumentation() | |
427 .SetTag("System") | |
428 .SetSummary("Modify a set of instances") | |
429 .SetRequestField("Resources", RestApiCallDocumentation::Type_JsonListOfStrings, | |
430 "List of the Orthanc identifiers of the patients/studies/series/instances of interest.", false) | |
431 .SetDescription("Start a job that will modify all the DICOM patients, studies, series or instances " | |
432 "whose identifiers are provided in the `Resources` field.") | |
433 .AddAnswerType(MimeType_Json, "The list of all the resources that have been altered by this modification"); | |
434 return; | |
435 } | |
436 | |
437 std::unique_ptr<DicomModification> modification(new DicomModification); | |
438 | |
439 Json::Value body; | |
440 ParseModifyRequest(body, *modification, call); | |
441 | |
442 modification->SetLevel(DetectModifyLevel(*modification)); | |
443 | |
444 SubmitBulkJob(modification, false /* not an anonymization */, call, body); | |
366 } | 445 } |
367 | 446 |
368 | 447 |
369 template <enum ResourceType resourceType> | 448 template <enum ResourceType resourceType> |
370 static void AnonymizeResource(RestApiPostCall& call) | 449 static void AnonymizeResource(RestApiPostCall& call) |
390 Json::Value body; | 469 Json::Value body; |
391 ParseAnonymizationRequest(body, *modification, call); | 470 ParseAnonymizationRequest(body, *modification, call); |
392 | 471 |
393 SubmitModificationJob(modification, true /* anonymization */, | 472 SubmitModificationJob(modification, true /* anonymization */, |
394 call, body, resourceType); | 473 call, body, resourceType); |
474 } | |
475 | |
476 | |
477 // New in Orthanc 1.9.4 | |
478 static void BulkAnonymize(RestApiPostCall& call) | |
479 { | |
480 if (call.IsDocumentation()) | |
481 { | |
482 OrthancRestApi::DocumentSubmitCommandsJob(call); | |
483 DocumentAnonymizationOptions(call); | |
484 call.GetDocumentation() | |
485 .SetTag("System") | |
486 .SetSummary("Anonymize a set of instances") | |
487 .SetRequestField("Resources", RestApiCallDocumentation::Type_JsonListOfStrings, | |
488 "List of the Orthanc identifiers of the patients/studies/series/instances of interest.", false) | |
489 .SetDescription("Start a job that will anonymize all the DICOM patients, studies, series or instances " | |
490 "whose identifiers are provided in the `Resources` field.") | |
491 .AddAnswerType(MimeType_Json, "The list of all the resources that have been created by this anonymization"); | |
492 return; | |
493 } | |
494 | |
495 std::unique_ptr<DicomModification> modification(new DicomModification); | |
496 | |
497 Json::Value body; | |
498 ParseAnonymizationRequest(body, *modification, call); | |
499 | |
500 SubmitBulkJob(modification, true /* anonymization */, call, body); | |
395 } | 501 } |
396 | 502 |
397 | 503 |
398 static void StoreCreatedInstance(std::string& id /* out */, | 504 static void StoreCreatedInstance(std::string& id /* out */, |
399 RestApiPostCall& call, | 505 RestApiPostCall& call, |
1052 { | 1158 { |
1053 Register("/instances/{id}/modify", ModifyInstance); | 1159 Register("/instances/{id}/modify", ModifyInstance); |
1054 Register("/series/{id}/modify", ModifyResource<ResourceType_Series>); | 1160 Register("/series/{id}/modify", ModifyResource<ResourceType_Series>); |
1055 Register("/studies/{id}/modify", ModifyResource<ResourceType_Study>); | 1161 Register("/studies/{id}/modify", ModifyResource<ResourceType_Study>); |
1056 Register("/patients/{id}/modify", ModifyResource<ResourceType_Patient>); | 1162 Register("/patients/{id}/modify", ModifyResource<ResourceType_Patient>); |
1163 Register("/tools/bulk-modify", BulkModify); | |
1057 | 1164 |
1058 Register("/instances/{id}/anonymize", AnonymizeInstance); | 1165 Register("/instances/{id}/anonymize", AnonymizeInstance); |
1059 Register("/series/{id}/anonymize", AnonymizeResource<ResourceType_Series>); | 1166 Register("/series/{id}/anonymize", AnonymizeResource<ResourceType_Series>); |
1060 Register("/studies/{id}/anonymize", AnonymizeResource<ResourceType_Study>); | 1167 Register("/studies/{id}/anonymize", AnonymizeResource<ResourceType_Study>); |
1061 Register("/patients/{id}/anonymize", AnonymizeResource<ResourceType_Patient>); | 1168 Register("/patients/{id}/anonymize", AnonymizeResource<ResourceType_Patient>); |
1169 Register("/tools/bulk-anonymize", BulkAnonymize); | |
1062 | 1170 |
1063 Register("/tools/create-dicom", CreateDicom); | 1171 Register("/tools/create-dicom", CreateDicom); |
1064 | 1172 |
1065 Register("/studies/{id}/split", SplitStudy); | 1173 Register("/studies/{id}/split", SplitStudy); |
1066 Register("/studies/{id}/merge", MergeStudy); | 1174 Register("/studies/{id}/merge", MergeStudy); |