Mercurial > hg > orthanc
annotate OrthancServer/Sources/OrthancWebDav.cpp @ 4796:94616af363ec filter-store-instance
added ReceivedCStoreInstanceFilter lua callback + OrthancPluginRegisterIncomingCStoreInstanceFilter in sdk
author | Alain Mazy <am@osimis.io> |
---|---|
date | Fri, 01 Oct 2021 18:36:45 +0200 |
parents | 569d9ef165b1 |
children | 70d2a97ca8cb 7053502fbf97 |
rev | line source |
---|---|
4240 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
4437
d9473bd5ed43
upgrade to year 2021
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4386
diff
changeset
|
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium |
4240 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "OrthancWebDav.h" | |
35 | |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
36 #include "../../OrthancFramework/Sources/Compression/ZipReader.h" |
4240 | 37 #include "../../OrthancFramework/Sources/DicomFormat/DicomArray.h" |
38 #include "../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" | |
39 #include "../../OrthancFramework/Sources/HttpServer/WebDavStorage.h" | |
4304 | 40 #include "../../OrthancFramework/Sources/Logging.h" |
4240 | 41 #include "Search/DatabaseLookup.h" |
42 #include "ServerContext.h" | |
43 | |
44 #include <boost/regex.hpp> | |
45 #include <boost/algorithm/string/predicate.hpp> | |
46 | |
47 | |
48 static const char* const BY_PATIENTS = "by-patients"; | |
49 static const char* const BY_STUDIES = "by-studies"; | |
4241 | 50 static const char* const BY_DATES = "by-dates"; |
4240 | 51 static const char* const BY_UIDS = "by-uids"; |
52 static const char* const UPLOADS = "uploads"; | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
53 static const char* const STUDY_INFO = "study.json"; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
54 static const char* const SERIES_INFO = "series.json"; |
4240 | 55 |
56 | |
57 namespace Orthanc | |
58 { | |
59 static boost::posix_time::ptime GetNow() | |
60 { | |
61 return boost::posix_time::second_clock::universal_time(); | |
62 } | |
63 | |
64 | |
65 static void LookupTime(boost::posix_time::ptime& target, | |
66 ServerContext& context, | |
67 const std::string& publicId, | |
4460
6831de40acd9
New metadata automatically computed at the series level: "RemoteAET"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
68 ResourceType level, |
4240 | 69 MetadataType metadata) |
70 { | |
71 std::string value; | |
4623
95ffe3b6ef7c
handling of revisions for metadata
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4588
diff
changeset
|
72 int64_t revision; // Ignored |
95ffe3b6ef7c
handling of revisions for metadata
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4588
diff
changeset
|
73 if (context.GetIndex().LookupMetadata(value, revision, publicId, level, metadata)) |
4240 | 74 { |
75 try | |
76 { | |
77 target = boost::posix_time::from_iso_string(value); | |
78 return; | |
79 } | |
80 catch (std::exception& e) | |
81 { | |
82 } | |
83 } | |
84 | |
85 target = GetNow(); | |
86 } | |
87 | |
88 | |
89 class OrthancWebDav::DicomIdentifiersVisitor : public ServerContext::ILookupVisitor | |
90 { | |
91 private: | |
92 ServerContext& context_; | |
93 bool isComplete_; | |
94 Collection& target_; | |
95 ResourceType level_; | |
96 | |
97 public: | |
98 DicomIdentifiersVisitor(ServerContext& context, | |
99 Collection& target, | |
100 ResourceType level) : | |
101 context_(context), | |
102 isComplete_(false), | |
103 target_(target), | |
104 level_(level) | |
105 { | |
106 } | |
107 | |
108 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE | |
109 { | |
110 return false; // (*) | |
111 } | |
112 | |
113 virtual void MarkAsComplete() ORTHANC_OVERRIDE | |
114 { | |
115 isComplete_ = true; // TODO | |
116 } | |
117 | |
118 virtual void Visit(const std::string& publicId, | |
119 const std::string& instanceId /* unused */, | |
120 const DicomMap& mainDicomTags, | |
121 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE | |
122 { | |
123 DicomTag tag(0, 0); | |
124 MetadataType timeMetadata; | |
125 | |
126 switch (level_) | |
127 { | |
128 case ResourceType_Study: | |
129 tag = DICOM_TAG_STUDY_INSTANCE_UID; | |
130 timeMetadata = MetadataType_LastUpdate; | |
131 break; | |
132 | |
133 case ResourceType_Series: | |
134 tag = DICOM_TAG_SERIES_INSTANCE_UID; | |
135 timeMetadata = MetadataType_LastUpdate; | |
136 break; | |
137 | |
138 case ResourceType_Instance: | |
139 tag = DICOM_TAG_SOP_INSTANCE_UID; | |
140 timeMetadata = MetadataType_Instance_ReceptionDate; | |
141 break; | |
142 | |
143 default: | |
144 throw OrthancException(ErrorCode_InternalError); | |
145 } | |
146 | |
147 std::string s; | |
148 if (mainDicomTags.LookupStringValue(s, tag, false) && | |
149 !s.empty()) | |
150 { | |
151 std::unique_ptr<Resource> resource; | |
152 | |
153 if (level_ == ResourceType_Instance) | |
154 { | |
155 FileInfo info; | |
4627
f7d5372b59b3
handling revisions of attachments
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4623
diff
changeset
|
156 int64_t revision; // Ignored |
f7d5372b59b3
handling revisions of attachments
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4623
diff
changeset
|
157 if (context_.GetIndex().LookupAttachment(info, revision, publicId, FileContentType_Dicom)) |
4240 | 158 { |
159 std::unique_ptr<File> f(new File(s + ".dcm")); | |
160 f->SetMimeType(MimeType_Dicom); | |
161 f->SetContentLength(info.GetUncompressedSize()); | |
162 resource.reset(f.release()); | |
163 } | |
164 } | |
165 else | |
166 { | |
167 resource.reset(new Folder(s)); | |
168 } | |
169 | |
170 if (resource.get() != NULL) | |
171 { | |
172 boost::posix_time::ptime t; | |
4460
6831de40acd9
New metadata automatically computed at the series level: "RemoteAET"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
173 LookupTime(t, context_, publicId, level_, timeMetadata); |
4240 | 174 resource->SetCreationTime(t); |
175 target_.AddResource(resource.release()); | |
176 } | |
177 } | |
178 } | |
179 }; | |
180 | |
181 | |
182 class OrthancWebDav::DicomFileVisitor : public ServerContext::ILookupVisitor | |
183 { | |
184 private: | |
185 ServerContext& context_; | |
186 bool success_; | |
187 std::string& target_; | |
188 boost::posix_time::ptime& time_; | |
189 | |
190 public: | |
191 DicomFileVisitor(ServerContext& context, | |
192 std::string& target, | |
193 boost::posix_time::ptime& time) : | |
194 context_(context), | |
195 success_(false), | |
196 target_(target), | |
197 time_(time) | |
198 { | |
199 } | |
200 | |
201 bool IsSuccess() const | |
202 { | |
203 return success_; | |
204 } | |
205 | |
206 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE | |
207 { | |
208 return false; // (*) | |
209 } | |
210 | |
211 virtual void MarkAsComplete() ORTHANC_OVERRIDE | |
212 { | |
213 } | |
214 | |
215 virtual void Visit(const std::string& publicId, | |
216 const std::string& instanceId /* unused */, | |
217 const DicomMap& mainDicomTags, | |
218 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE | |
219 { | |
220 if (success_) | |
221 { | |
222 success_ = false; // Two matches => Error | |
223 } | |
224 else | |
225 { | |
4460
6831de40acd9
New metadata automatically computed at the series level: "RemoteAET"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
226 LookupTime(time_, context_, publicId, ResourceType_Instance, MetadataType_Instance_ReceptionDate); |
4240 | 227 context_.ReadDicom(target_, publicId); |
228 success_ = true; | |
229 } | |
230 } | |
231 }; | |
232 | |
233 | |
234 class OrthancWebDav::OrthancJsonVisitor : public ServerContext::ILookupVisitor | |
235 { | |
236 private: | |
237 ServerContext& context_; | |
238 bool success_; | |
239 std::string& target_; | |
240 ResourceType level_; | |
241 | |
242 public: | |
243 OrthancJsonVisitor(ServerContext& context, | |
244 std::string& target, | |
245 ResourceType level) : | |
246 context_(context), | |
247 success_(false), | |
248 target_(target), | |
249 level_(level) | |
250 { | |
251 } | |
252 | |
253 bool IsSuccess() const | |
254 { | |
255 return success_; | |
256 } | |
257 | |
258 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE | |
259 { | |
260 return false; // (*) | |
261 } | |
262 | |
263 virtual void MarkAsComplete() ORTHANC_OVERRIDE | |
264 { | |
265 } | |
266 | |
267 virtual void Visit(const std::string& publicId, | |
268 const std::string& instanceId /* unused */, | |
269 const DicomMap& mainDicomTags, | |
270 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE | |
271 { | |
4554 | 272 Json::Value resource; |
4697
569d9ef165b1
Added "short", "simplify" and/or "full" options to control the format of DICOM tags wherever possible
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4627
diff
changeset
|
273 if (context_.GetIndex().ExpandResource(resource, publicId, level_, DicomToJsonFormat_Human)) |
4240 | 274 { |
275 if (success_) | |
276 { | |
277 success_ = false; // Two matches => Error | |
278 } | |
279 else | |
280 { | |
4554 | 281 target_ = resource.toStyledString(); |
4240 | 282 |
283 // Replace UNIX newlines with DOS newlines | |
284 boost::replace_all(target_, "\n", "\r\n"); | |
285 | |
286 success_ = true; | |
287 } | |
288 } | |
289 } | |
290 }; | |
291 | |
292 | |
293 class OrthancWebDav::ResourcesIndex : public boost::noncopyable | |
294 { | |
295 public: | |
296 typedef std::map<std::string, std::string> Map; | |
297 | |
298 private: | |
299 ServerContext& context_; | |
300 ResourceType level_; | |
301 std::string template_; | |
302 Map pathToResource_; | |
303 Map resourceToPath_; | |
304 | |
305 void CheckInvariants() | |
306 { | |
307 #ifndef NDEBUG | |
308 assert(pathToResource_.size() == resourceToPath_.size()); | |
309 | |
310 for (Map::const_iterator it = pathToResource_.begin(); it != pathToResource_.end(); ++it) | |
311 { | |
312 assert(resourceToPath_[it->second] == it->first); | |
313 } | |
314 | |
315 for (Map::const_iterator it = resourceToPath_.begin(); it != resourceToPath_.end(); ++it) | |
316 { | |
317 assert(pathToResource_[it->second] == it->first); | |
318 } | |
319 #endif | |
320 } | |
321 | |
322 void AddTags(DicomMap& target, | |
323 const std::string& resourceId, | |
324 ResourceType tagsFromLevel) | |
325 { | |
326 DicomMap tags; | |
327 if (context_.GetIndex().GetMainDicomTags(tags, resourceId, level_, tagsFromLevel)) | |
328 { | |
329 target.Merge(tags); | |
330 } | |
331 } | |
332 | |
333 void Register(const std::string& resourceId) | |
334 { | |
335 // Don't register twice the same resource | |
336 if (resourceToPath_.find(resourceId) == resourceToPath_.end()) | |
337 { | |
338 std::string name = template_; | |
339 | |
340 DicomMap tags; | |
341 | |
342 AddTags(tags, resourceId, level_); | |
343 | |
344 if (level_ == ResourceType_Study) | |
345 { | |
346 AddTags(tags, resourceId, ResourceType_Patient); | |
347 } | |
348 | |
349 DicomArray arr(tags); | |
350 for (size_t i = 0; i < arr.GetSize(); i++) | |
351 { | |
352 const DicomElement& element = arr.GetElement(i); | |
353 if (!element.GetValue().IsNull() && | |
354 !element.GetValue().IsBinary()) | |
355 { | |
356 const std::string tag = FromDcmtkBridge::GetTagName(element.GetTag(), ""); | |
357 boost::replace_all(name, "{{" + tag + "}}", element.GetValue().GetContent()); | |
358 } | |
359 } | |
360 | |
361 // Blank the tags that were not matched | |
362 static const boost::regex REGEX_BLANK_TAGS("{{.*?}}"); // non-greedy match | |
363 name = boost::regex_replace(name, REGEX_BLANK_TAGS, ""); | |
364 | |
365 // UTF-8 characters cannot be used on Windows XP | |
366 name = Toolbox::ConvertToAscii(name); | |
367 boost::replace_all(name, "/", ""); | |
368 boost::replace_all(name, "\\", ""); | |
369 | |
370 // Trim sequences of spaces as one single space | |
371 static const boost::regex REGEX_TRIM_SPACES("{{.*?}}"); | |
372 name = boost::regex_replace(name, REGEX_TRIM_SPACES, " "); | |
373 name = Toolbox::StripSpaces(name); | |
374 | |
375 size_t count = 0; | |
376 for (;;) | |
377 { | |
378 std::string path = name; | |
379 if (count > 0) | |
380 { | |
381 path += " (" + boost::lexical_cast<std::string>(count) + ")"; | |
382 } | |
383 | |
384 if (pathToResource_.find(path) == pathToResource_.end()) | |
385 { | |
386 pathToResource_[path] = resourceId; | |
387 resourceToPath_[resourceId] = path; | |
388 return; | |
389 } | |
390 | |
391 count++; | |
392 } | |
393 | |
394 throw OrthancException(ErrorCode_InternalError); | |
395 } | |
396 } | |
397 | |
398 public: | |
399 ResourcesIndex(ServerContext& context, | |
400 ResourceType level, | |
401 const std::string& templateString) : | |
402 context_(context), | |
403 level_(level), | |
404 template_(templateString) | |
405 { | |
406 } | |
407 | |
408 ResourceType GetLevel() const | |
409 { | |
410 return level_; | |
411 } | |
412 | |
413 void Refresh(std::set<std::string>& removedPaths /* out */, | |
414 const std::set<std::string>& resources) | |
415 { | |
416 CheckInvariants(); | |
417 | |
418 // Detect the resources that have been removed since last refresh | |
419 removedPaths.clear(); | |
420 std::set<std::string> removedResources; | |
421 | |
422 for (Map::iterator it = resourceToPath_.begin(); it != resourceToPath_.end(); ++it) | |
423 { | |
424 if (resources.find(it->first) == resources.end()) | |
425 { | |
426 const std::string& path = it->second; | |
427 | |
428 assert(pathToResource_.find(path) != pathToResource_.end()); | |
429 pathToResource_.erase(path); | |
430 removedPaths.insert(path); | |
431 | |
432 removedResources.insert(it->first); // Delay the removal to avoid disturbing the iterator | |
433 } | |
434 } | |
435 | |
436 // Remove the missing resources | |
437 for (std::set<std::string>::const_iterator it = removedResources.begin(); it != removedResources.end(); ++it) | |
438 { | |
439 assert(resourceToPath_.find(*it) != resourceToPath_.end()); | |
440 resourceToPath_.erase(*it); | |
441 } | |
442 | |
443 CheckInvariants(); | |
444 | |
445 for (std::set<std::string>::const_iterator it = resources.begin(); it != resources.end(); ++it) | |
446 { | |
447 Register(*it); | |
448 } | |
449 | |
450 CheckInvariants(); | |
451 } | |
452 | |
453 const Map& GetPathToResource() const | |
454 { | |
455 return pathToResource_; | |
456 } | |
457 }; | |
458 | |
459 | |
460 class OrthancWebDav::InstancesOfSeries : public INode | |
461 { | |
462 private: | |
463 ServerContext& context_; | |
464 std::string parentSeries_; | |
465 | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
466 static bool LookupInstanceId(std::string& instanceId, |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
467 const UriComponents& path) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
468 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
469 if (path.size() == 1 && |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
470 boost::ends_with(path[0], ".dcm")) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
471 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
472 instanceId = path[0].substr(0, path[0].size() - 4); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
473 return true; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
474 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
475 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
476 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
477 return false; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
478 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
479 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
480 |
4240 | 481 public: |
482 InstancesOfSeries(ServerContext& context, | |
483 const std::string& parentSeries) : | |
484 context_(context), | |
485 parentSeries_(parentSeries) | |
486 { | |
487 } | |
488 | |
489 virtual bool ListCollection(IWebDavBucket::Collection& target, | |
490 const UriComponents& path) ORTHANC_OVERRIDE | |
491 { | |
492 if (path.empty()) | |
493 { | |
494 std::list<std::string> resources; | |
495 try | |
496 { | |
497 context_.GetIndex().GetChildren(resources, parentSeries_); | |
498 } | |
499 catch (OrthancException&) | |
500 { | |
501 // Unknown (or deleted) parent series | |
502 return false; | |
503 } | |
504 | |
505 for (std::list<std::string>::const_iterator | |
506 it = resources.begin(); it != resources.end(); ++it) | |
507 { | |
508 boost::posix_time::ptime time; | |
4460
6831de40acd9
New metadata automatically computed at the series level: "RemoteAET"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
509 LookupTime(time, context_, *it, ResourceType_Instance, MetadataType_Instance_ReceptionDate); |
4240 | 510 |
511 FileInfo info; | |
4627
f7d5372b59b3
handling revisions of attachments
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4623
diff
changeset
|
512 int64_t revision; // Ignored |
f7d5372b59b3
handling revisions of attachments
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4623
diff
changeset
|
513 if (context_.GetIndex().LookupAttachment(info, revision, *it, FileContentType_Dicom)) |
4240 | 514 { |
515 std::unique_ptr<File> resource(new File(*it + ".dcm")); | |
516 resource->SetMimeType(MimeType_Dicom); | |
517 resource->SetContentLength(info.GetUncompressedSize()); | |
518 resource->SetCreationTime(time); | |
519 target.AddResource(resource.release()); | |
520 } | |
521 } | |
522 | |
523 return true; | |
524 } | |
525 else | |
526 { | |
527 return false; | |
528 } | |
529 } | |
530 | |
531 virtual bool GetFileContent(MimeType& mime, | |
532 std::string& content, | |
533 boost::posix_time::ptime& time, | |
534 const UriComponents& path) ORTHANC_OVERRIDE | |
535 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
536 std::string instanceId; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
537 if (LookupInstanceId(instanceId, path)) |
4240 | 538 { |
539 try | |
540 { | |
541 mime = MimeType_Dicom; | |
542 context_.ReadDicom(content, instanceId); | |
4460
6831de40acd9
New metadata automatically computed at the series level: "RemoteAET"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
543 LookupTime(time, context_, instanceId, ResourceType_Instance, MetadataType_Instance_ReceptionDate); |
4240 | 544 return true; |
545 } | |
546 catch (OrthancException&) | |
547 { | |
548 // File was removed | |
549 return false; | |
550 } | |
551 } | |
552 else | |
553 { | |
554 return false; | |
555 } | |
556 } | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
557 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
558 virtual bool DeleteItem(const UriComponents& path) ORTHANC_OVERRIDE |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
559 { |
4252 | 560 if (path.empty()) |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
561 { |
4252 | 562 // Delete all |
563 std::list<std::string> resources; | |
564 try | |
565 { | |
566 context_.GetIndex().GetChildren(resources, parentSeries_); | |
567 } | |
568 catch (OrthancException&) | |
569 { | |
570 // Unknown (or deleted) parent series | |
571 return true; | |
572 } | |
573 | |
574 for (std::list<std::string>::const_iterator it = resources.begin(); | |
575 it != resources.end(); ++it) | |
576 { | |
577 Json::Value info; | |
578 context_.DeleteResource(info, *it, ResourceType_Instance); | |
579 } | |
580 | |
581 return true; | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
582 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
583 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
584 { |
4252 | 585 std::string instanceId; |
586 if (LookupInstanceId(instanceId, path)) | |
587 { | |
588 Json::Value info; | |
589 return context_.DeleteResource(info, instanceId, ResourceType_Instance); | |
590 } | |
591 else | |
592 { | |
593 return false; | |
594 } | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
595 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
596 } |
4240 | 597 }; |
598 | |
599 | |
600 | |
601 /** | |
602 * The "InternalNode" class corresponds to a non-leaf node in the | |
603 * WebDAV tree, that only contains subfolders (no file). | |
604 * | |
605 * TODO: Implement a LRU index to dynamically remove the oldest | |
606 * children on high RAM usage. | |
607 **/ | |
608 class OrthancWebDav::InternalNode : public INode | |
609 { | |
610 private: | |
611 typedef std::map<std::string, INode*> Children; | |
612 | |
613 Children children_; | |
614 | |
615 INode* GetChild(const std::string& path) // Don't delete the result pointer! | |
616 { | |
617 Children::const_iterator child = children_.find(path); | |
618 if (child == children_.end()) | |
619 { | |
4253 | 620 INode* node = CreateSubfolder(path); |
4240 | 621 |
4253 | 622 if (node == NULL) |
4240 | 623 { |
624 return NULL; | |
625 } | |
626 else | |
627 { | |
4253 | 628 children_[path] = node; |
629 return node; | |
4240 | 630 } |
631 } | |
632 else | |
633 { | |
634 assert(child->second != NULL); | |
635 return child->second; | |
636 } | |
637 } | |
638 | |
639 protected: | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
640 void InvalidateSubfolder(const std::string& path) |
4240 | 641 { |
642 Children::iterator child = children_.find(path); | |
643 if (child != children_.end()) | |
644 { | |
645 assert(child->second != NULL); | |
646 delete child->second; | |
647 children_.erase(child); | |
648 } | |
649 } | |
650 | |
651 virtual void Refresh() = 0; | |
652 | |
653 virtual bool ListSubfolders(IWebDavBucket::Collection& target) = 0; | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
654 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
655 virtual INode* CreateSubfolder(const std::string& path) = 0; |
4240 | 656 |
657 public: | |
658 virtual ~InternalNode() | |
659 { | |
660 for (Children::iterator it = children_.begin(); it != children_.end(); ++it) | |
661 { | |
662 assert(it->second != NULL); | |
663 delete it->second; | |
664 } | |
665 } | |
666 | |
667 virtual bool ListCollection(IWebDavBucket::Collection& target, | |
668 const UriComponents& path) | |
669 ORTHANC_OVERRIDE ORTHANC_FINAL | |
670 { | |
671 Refresh(); | |
672 | |
673 if (path.empty()) | |
674 { | |
675 return ListSubfolders(target); | |
676 } | |
677 else | |
678 { | |
679 // Recursivity | |
680 INode* child = GetChild(path[0]); | |
681 if (child == NULL) | |
682 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
683 // Must be "true" to allow DELETE on folders that are |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
684 // automatically removed through recursive deletion |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
685 return true; |
4240 | 686 } |
687 else | |
688 { | |
689 UriComponents subpath(path.begin() + 1, path.end()); | |
690 return child->ListCollection(target, subpath); | |
691 } | |
692 } | |
693 } | |
694 | |
695 virtual bool GetFileContent(MimeType& mime, | |
696 std::string& content, | |
697 boost::posix_time::ptime& time, | |
698 const UriComponents& path) | |
699 ORTHANC_OVERRIDE ORTHANC_FINAL | |
700 { | |
701 if (path.empty()) | |
702 { | |
703 return false; // An internal node doesn't correspond to a file | |
704 } | |
705 else | |
706 { | |
707 // Recursivity | |
708 Refresh(); | |
709 | |
710 INode* child = GetChild(path[0]); | |
711 if (child == NULL) | |
712 { | |
713 return false; | |
714 } | |
715 else | |
716 { | |
717 UriComponents subpath(path.begin() + 1, path.end()); | |
718 return child->GetFileContent(mime, content, time, subpath); | |
719 } | |
720 } | |
721 } | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
722 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
723 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
724 virtual bool DeleteItem(const UriComponents& path) ORTHANC_OVERRIDE ORTHANC_FINAL |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
725 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
726 Refresh(); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
727 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
728 if (path.empty()) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
729 { |
4252 | 730 IWebDavBucket::Collection collection; |
731 if (ListSubfolders(collection)) | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
732 { |
4252 | 733 std::set<std::string> content; |
734 collection.ListDisplayNames(content); | |
735 | |
736 for (std::set<std::string>::const_iterator | |
737 it = content.begin(); it != content.end(); ++it) | |
738 { | |
739 INode* node = GetChild(*it); | |
740 if (node) | |
741 { | |
742 node->DeleteItem(path); | |
743 } | |
744 } | |
745 | |
746 return true; | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
747 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
748 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
749 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
750 return false; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
751 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
752 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
753 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
754 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
755 INode* child = GetChild(path[0]); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
756 if (child == NULL) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
757 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
758 return true; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
759 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
760 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
761 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
762 // Recursivity |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
763 UriComponents subpath(path.begin() + 1, path.end()); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
764 return child->DeleteItem(subpath); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
765 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
766 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
767 } |
4240 | 768 }; |
769 | |
770 | |
771 class OrthancWebDav::ListOfResources : public InternalNode | |
772 { | |
773 private: | |
774 ServerContext& context_; | |
775 const Templates& templates_; | |
776 std::unique_ptr<ResourcesIndex> index_; | |
777 MetadataType timeMetadata_; | |
778 | |
779 protected: | |
780 virtual void Refresh() ORTHANC_OVERRIDE ORTHANC_FINAL | |
781 { | |
782 std::list<std::string> resources; | |
783 GetCurrentResources(resources); | |
784 | |
785 std::set<std::string> removedPaths; | |
786 index_->Refresh(removedPaths, std::set<std::string>(resources.begin(), resources.end())); | |
787 | |
788 // Remove the children whose associated resource doesn't exist anymore | |
789 for (std::set<std::string>::const_iterator | |
790 it = removedPaths.begin(); it != removedPaths.end(); ++it) | |
791 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
792 InvalidateSubfolder(*it); |
4240 | 793 } |
794 } | |
795 | |
796 virtual bool ListSubfolders(IWebDavBucket::Collection& target) ORTHANC_OVERRIDE ORTHANC_FINAL | |
797 { | |
798 if (index_->GetLevel() == ResourceType_Instance) | |
799 { | |
800 // Not a collection, no subfolders | |
801 return false; | |
802 } | |
803 else | |
804 { | |
805 const ResourcesIndex::Map& paths = index_->GetPathToResource(); | |
806 | |
807 for (ResourcesIndex::Map::const_iterator it = paths.begin(); it != paths.end(); ++it) | |
808 { | |
809 boost::posix_time::ptime time; | |
4460
6831de40acd9
New metadata automatically computed at the series level: "RemoteAET"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4437
diff
changeset
|
810 LookupTime(time, context_, it->second, index_->GetLevel(), timeMetadata_); |
4240 | 811 |
812 std::unique_ptr<IWebDavBucket::Resource> resource(new IWebDavBucket::Folder(it->first)); | |
813 resource->SetCreationTime(time); | |
814 target.AddResource(resource.release()); | |
815 } | |
816 | |
817 return true; | |
818 } | |
819 } | |
820 | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
821 virtual INode* CreateSubfolder(const std::string& path) ORTHANC_OVERRIDE ORTHANC_FINAL |
4240 | 822 { |
823 ResourcesIndex::Map::const_iterator resource = index_->GetPathToResource().find(path); | |
824 if (resource == index_->GetPathToResource().end()) | |
825 { | |
826 return NULL; | |
827 } | |
828 else | |
829 { | |
830 return CreateResourceNode(resource->second); | |
831 } | |
832 } | |
833 | |
834 ServerContext& GetContext() const | |
835 { | |
836 return context_; | |
837 } | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
838 |
4240 | 839 virtual void GetCurrentResources(std::list<std::string>& resources) = 0; |
840 | |
841 virtual INode* CreateResourceNode(const std::string& resource) = 0; | |
842 | |
843 public: | |
844 ListOfResources(ServerContext& context, | |
845 ResourceType level, | |
846 const Templates& templates) : | |
847 context_(context), | |
848 templates_(templates) | |
849 { | |
850 Templates::const_iterator t = templates.find(level); | |
851 if (t == templates.end()) | |
852 { | |
853 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
854 } | |
855 | |
856 index_.reset(new ResourcesIndex(context, level, t->second)); | |
857 | |
858 if (level == ResourceType_Instance) | |
859 { | |
860 timeMetadata_ = MetadataType_Instance_ReceptionDate; | |
861 } | |
862 else | |
863 { | |
864 timeMetadata_ = MetadataType_LastUpdate; | |
865 } | |
866 } | |
867 | |
868 ResourceType GetLevel() const | |
869 { | |
870 return index_->GetLevel(); | |
871 } | |
872 | |
873 const Templates& GetTemplates() const | |
874 { | |
875 return templates_; | |
876 } | |
877 }; | |
878 | |
879 | |
880 | |
881 class OrthancWebDav::SingleDicomResource : public ListOfResources | |
882 { | |
883 private: | |
884 std::string parentId_; | |
885 | |
886 protected: | |
887 virtual void GetCurrentResources(std::list<std::string>& resources) ORTHANC_OVERRIDE | |
888 { | |
889 try | |
890 { | |
891 GetContext().GetIndex().GetChildren(resources, parentId_); | |
892 } | |
893 catch (OrthancException&) | |
894 { | |
895 // Unknown parent resource | |
896 resources.clear(); | |
897 } | |
898 } | |
899 | |
900 virtual INode* CreateResourceNode(const std::string& resource) ORTHANC_OVERRIDE | |
901 { | |
902 if (GetLevel() == ResourceType_Instance) | |
903 { | |
904 return NULL; | |
905 } | |
906 else if (GetLevel() == ResourceType_Series) | |
907 { | |
908 return new InstancesOfSeries(GetContext(), resource); | |
909 } | |
910 else | |
911 { | |
912 ResourceType l = GetChildResourceType(GetLevel()); | |
913 return new SingleDicomResource(GetContext(), l, resource, GetTemplates()); | |
914 } | |
915 } | |
916 | |
917 public: | |
918 SingleDicomResource(ServerContext& context, | |
919 ResourceType level, | |
920 const std::string& parentId, | |
921 const Templates& templates) : | |
922 ListOfResources(context, level, templates), | |
923 parentId_(parentId) | |
924 { | |
925 } | |
926 }; | |
927 | |
928 | |
929 class OrthancWebDav::RootNode : public ListOfResources | |
930 { | |
931 protected: | |
932 virtual void GetCurrentResources(std::list<std::string>& resources) ORTHANC_OVERRIDE | |
933 { | |
934 GetContext().GetIndex().GetAllUuids(resources, GetLevel()); | |
935 } | |
936 | |
937 virtual INode* CreateResourceNode(const std::string& resource) ORTHANC_OVERRIDE | |
938 { | |
939 if (GetLevel() == ResourceType_Series) | |
940 { | |
941 return new InstancesOfSeries(GetContext(), resource); | |
942 } | |
943 else | |
944 { | |
945 ResourceType l = GetChildResourceType(GetLevel()); | |
946 return new SingleDicomResource(GetContext(), l, resource, GetTemplates()); | |
947 } | |
948 } | |
949 | |
950 public: | |
951 RootNode(ServerContext& context, | |
952 ResourceType level, | |
953 const Templates& templates) : | |
954 ListOfResources(context, level, templates) | |
955 { | |
956 } | |
957 }; | |
958 | |
959 | |
960 class OrthancWebDav::ListOfStudiesByDate : public ListOfResources | |
961 { | |
962 private: | |
963 std::string year_; | |
964 std::string month_; | |
965 | |
966 class Visitor : public ServerContext::ILookupVisitor | |
967 { | |
968 private: | |
969 std::list<std::string>& resources_; | |
970 | |
971 public: | |
4253 | 972 explicit Visitor(std::list<std::string>& resources) : |
4240 | 973 resources_(resources) |
974 { | |
975 } | |
976 | |
977 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE | |
978 { | |
979 return false; // (*) | |
980 } | |
981 | |
982 virtual void MarkAsComplete() ORTHANC_OVERRIDE | |
983 { | |
984 } | |
985 | |
986 virtual void Visit(const std::string& publicId, | |
987 const std::string& instanceId /* unused */, | |
988 const DicomMap& mainDicomTags, | |
989 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE | |
990 { | |
991 resources_.push_back(publicId); | |
992 } | |
993 }; | |
994 | |
995 protected: | |
996 virtual void GetCurrentResources(std::list<std::string>& resources) ORTHANC_OVERRIDE | |
997 { | |
998 DatabaseLookup query; | |
999 query.AddRestConstraint(DICOM_TAG_STUDY_DATE, year_ + month_ + "01-" + year_ + month_ + "31", | |
1000 true /* case sensitive */, true /* mandatory tag */); | |
1001 | |
1002 Visitor visitor(resources); | |
1003 GetContext().Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */); | |
1004 } | |
1005 | |
1006 virtual INode* CreateResourceNode(const std::string& resource) ORTHANC_OVERRIDE | |
1007 { | |
1008 return new SingleDicomResource(GetContext(), ResourceType_Series, resource, GetTemplates()); | |
1009 } | |
1010 | |
1011 public: | |
1012 ListOfStudiesByDate(ServerContext& context, | |
1013 const std::string& year, | |
1014 const std::string& month, | |
1015 const Templates& templates) : | |
1016 ListOfResources(context, ResourceType_Study, templates), | |
1017 year_(year), | |
1018 month_(month) | |
1019 { | |
1020 if (year.size() != 4 || | |
1021 month.size() != 2) | |
1022 { | |
1023 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
1024 } | |
1025 } | |
1026 }; | |
1027 | |
1028 | |
1029 class OrthancWebDav::ListOfStudiesByMonth : public InternalNode | |
1030 { | |
1031 private: | |
1032 ServerContext& context_; | |
1033 std::string year_; | |
1034 const Templates& templates_; | |
1035 | |
1036 class Visitor : public ServerContext::ILookupVisitor | |
1037 { | |
1038 private: | |
1039 std::set<std::string> months_; | |
1040 | |
1041 public: | |
1042 const std::set<std::string>& GetMonths() const | |
1043 { | |
1044 return months_; | |
1045 } | |
1046 | |
1047 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE | |
1048 { | |
1049 return false; // (*) | |
1050 } | |
1051 | |
1052 virtual void MarkAsComplete() ORTHANC_OVERRIDE | |
1053 { | |
1054 } | |
1055 | |
1056 virtual void Visit(const std::string& publicId, | |
1057 const std::string& instanceId /* unused */, | |
1058 const DicomMap& mainDicomTags, | |
1059 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE | |
1060 { | |
1061 std::string s; | |
1062 if (mainDicomTags.LookupStringValue(s, DICOM_TAG_STUDY_DATE, false) && | |
1063 s.size() == 8) | |
1064 { | |
1065 months_.insert(s.substr(4, 2)); // Get the month from "YYYYMMDD" | |
1066 } | |
1067 } | |
1068 }; | |
1069 | |
1070 protected: | |
1071 virtual void Refresh() ORTHANC_OVERRIDE | |
1072 { | |
1073 } | |
1074 | |
1075 virtual bool ListSubfolders(IWebDavBucket::Collection& target) ORTHANC_OVERRIDE | |
1076 { | |
1077 DatabaseLookup query; | |
1078 query.AddRestConstraint(DICOM_TAG_STUDY_DATE, year_ + "0101-" + year_ + "1231", | |
1079 true /* case sensitive */, true /* mandatory tag */); | |
1080 | |
1081 Visitor visitor; | |
1082 context_.Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */); | |
1083 | |
1084 for (std::set<std::string>::const_iterator it = visitor.GetMonths().begin(); | |
1085 it != visitor.GetMonths().end(); ++it) | |
1086 { | |
1087 target.AddResource(new IWebDavBucket::Folder(year_ + "-" + *it)); | |
1088 } | |
1089 | |
1090 return true; | |
1091 } | |
1092 | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1093 virtual INode* CreateSubfolder(const std::string& path) ORTHANC_OVERRIDE |
4240 | 1094 { |
1095 if (path.size() != 7) // Format: "YYYY-MM" | |
1096 { | |
1097 throw OrthancException(ErrorCode_InternalError); | |
1098 } | |
1099 else | |
1100 { | |
1101 const std::string year = path.substr(0, 4); | |
1102 const std::string month = path.substr(5, 2); | |
1103 return new ListOfStudiesByDate(context_, year, month, templates_); | |
1104 } | |
1105 } | |
1106 | |
1107 public: | |
1108 ListOfStudiesByMonth(ServerContext& context, | |
1109 const std::string& year, | |
1110 const Templates& templates) : | |
1111 context_(context), | |
1112 year_(year), | |
1113 templates_(templates) | |
1114 { | |
1115 if (year_.size() != 4) | |
1116 { | |
1117 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
1118 } | |
1119 } | |
1120 }; | |
1121 | |
1122 | |
1123 class OrthancWebDav::ListOfStudiesByYear : public InternalNode | |
1124 { | |
1125 private: | |
1126 ServerContext& context_; | |
1127 const Templates& templates_; | |
1128 | |
1129 protected: | |
1130 virtual void Refresh() ORTHANC_OVERRIDE | |
1131 { | |
1132 } | |
1133 | |
1134 virtual bool ListSubfolders(IWebDavBucket::Collection& target) ORTHANC_OVERRIDE | |
1135 { | |
1136 std::list<std::string> resources; | |
1137 context_.GetIndex().GetAllUuids(resources, ResourceType_Study); | |
1138 | |
1139 std::set<std::string> years; | |
1140 | |
1141 for (std::list<std::string>::const_iterator it = resources.begin(); it != resources.end(); ++it) | |
1142 { | |
1143 DicomMap tags; | |
1144 std::string studyDate; | |
1145 if (context_.GetIndex().GetMainDicomTags(tags, *it, ResourceType_Study, ResourceType_Study) && | |
1146 tags.LookupStringValue(studyDate, DICOM_TAG_STUDY_DATE, false) && | |
1147 studyDate.size() == 8) | |
1148 { | |
1149 years.insert(studyDate.substr(0, 4)); // Get the year from "YYYYMMDD" | |
1150 } | |
1151 } | |
1152 | |
1153 for (std::set<std::string>::const_iterator it = years.begin(); it != years.end(); ++it) | |
1154 { | |
1155 target.AddResource(new IWebDavBucket::Folder(*it)); | |
1156 } | |
1157 | |
1158 return true; | |
1159 } | |
1160 | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1161 virtual INode* CreateSubfolder(const std::string& path) ORTHANC_OVERRIDE |
4240 | 1162 { |
1163 return new ListOfStudiesByMonth(context_, path, templates_); | |
1164 } | |
1165 | |
1166 public: | |
1167 ListOfStudiesByYear(ServerContext& context, | |
1168 const Templates& templates) : | |
1169 context_(context), | |
1170 templates_(templates) | |
1171 { | |
1172 } | |
1173 }; | |
1174 | |
1175 | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1176 class OrthancWebDav::DicomDeleteVisitor : public ServerContext::ILookupVisitor |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1177 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1178 private: |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1179 ServerContext& context_; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1180 ResourceType level_; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1181 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1182 public: |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1183 DicomDeleteVisitor(ServerContext& context, |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1184 ResourceType level) : |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1185 context_(context), |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1186 level_(level) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1187 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1188 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1189 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1190 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1191 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1192 return false; // (*) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1193 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1194 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1195 virtual void MarkAsComplete() ORTHANC_OVERRIDE |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1196 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1197 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1198 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1199 virtual void Visit(const std::string& publicId, |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1200 const std::string& instanceId /* unused */, |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1201 const DicomMap& mainDicomTags /* unused */, |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1202 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1203 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1204 Json::Value info; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1205 context_.DeleteResource(info, publicId, level_); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1206 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1207 }; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1208 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1209 |
4240 | 1210 void OrthancWebDav::AddVirtualFile(Collection& collection, |
1211 const UriComponents& path, | |
1212 const std::string& filename) | |
1213 { | |
1214 MimeType mime; | |
1215 std::string content; | |
4246 | 1216 boost::posix_time::ptime modification; // Unused, let the date be set to "GetNow()" |
4240 | 1217 |
1218 UriComponents p = path; | |
1219 p.push_back(filename); | |
1220 | |
1221 if (GetFileContent(mime, content, modification, p)) | |
1222 { | |
1223 std::unique_ptr<File> f(new File(filename)); | |
1224 f->SetMimeType(mime); | |
1225 f->SetContentLength(content.size()); | |
1226 collection.AddResource(f.release()); | |
1227 } | |
1228 } | |
1229 | |
1230 | |
1231 void OrthancWebDav::UploadWorker(OrthancWebDav* that) | |
1232 { | |
1233 assert(that != NULL); | |
1234 | |
1235 boost::posix_time::ptime lastModification = GetNow(); | |
1236 | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1237 while (that->uploadRunning_) |
4240 | 1238 { |
1239 std::unique_ptr<IDynamicObject> obj(that->uploadQueue_.Dequeue(100)); | |
1240 if (obj.get() != NULL) | |
1241 { | |
1242 that->Upload(reinterpret_cast<const SingleValueObject<std::string>&>(*obj).GetValue()); | |
1243 lastModification = GetNow(); | |
1244 } | |
4245
c70df925151e
RequestOrigin_WebDav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4244
diff
changeset
|
1245 else if (GetNow() - lastModification > boost::posix_time::seconds(30)) |
4240 | 1246 { |
4245
c70df925151e
RequestOrigin_WebDav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4244
diff
changeset
|
1247 /** |
c70df925151e
RequestOrigin_WebDav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4244
diff
changeset
|
1248 * After every 30 seconds of inactivity, remove the empty |
c70df925151e
RequestOrigin_WebDav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4244
diff
changeset
|
1249 * folders. This delay is needed to avoid removing |
c70df925151e
RequestOrigin_WebDav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4244
diff
changeset
|
1250 * just-created folders before the remote WebDAV has time to |
c70df925151e
RequestOrigin_WebDav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4244
diff
changeset
|
1251 * write files into it. |
c70df925151e
RequestOrigin_WebDav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4244
diff
changeset
|
1252 **/ |
4268
0ae2ca210077
new macro TLOG() to replace VLOG() for trace logs with a category
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4264
diff
changeset
|
1253 LOG(TRACE) << "Cleaning up the empty WebDAV upload folders"; |
4240 | 1254 that->uploads_.RemoveEmptyFolders(); |
1255 lastModification = GetNow(); | |
1256 } | |
1257 } | |
1258 } | |
1259 | |
1260 | |
1261 void OrthancWebDav::Upload(const std::string& path) | |
1262 { | |
1263 UriComponents uri; | |
1264 Toolbox::SplitUriComponents(uri, path); | |
1265 | |
1266 LOG(INFO) << "Upload from WebDAV: " << path; | |
1267 | |
1268 MimeType mime; | |
1269 std::string content; | |
1270 boost::posix_time::ptime time; | |
1271 if (uploads_.GetFileContent(mime, content, time, uri)) | |
1272 { | |
4244
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1273 bool success = false; |
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1274 |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1275 if (ZipReader::IsZipMemoryBuffer(content)) |
4240 | 1276 { |
4374
79ef2b6d8e76
there will be a 1.8.2 release before 1.9.0
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4358
diff
changeset
|
1277 // New in Orthanc 1.8.2 |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1278 std::unique_ptr<ZipReader> reader(ZipReader::CreateFromMemory(content)); |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1279 |
4386 | 1280 std::string filename, uncompressedFile; |
1281 while (reader->ReadNextFile(filename, uncompressedFile)) | |
4244
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1282 { |
4386 | 1283 if (!uncompressedFile.empty()) |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1284 { |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1285 LOG(INFO) << "Uploading DICOM file extracted from a ZIP archive in WebDAV: " << filename; |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1286 |
4508
8f9090b137f1
Optimization in C-STORE SCP by avoiding an unnecessary DICOM parsing
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4460
diff
changeset
|
1287 std::unique_ptr<DicomInstanceToStore> instance(DicomInstanceToStore::CreateFromBuffer(uncompressedFile)); |
8f9090b137f1
Optimization in C-STORE SCP by avoiding an unnecessary DICOM parsing
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4460
diff
changeset
|
1288 instance->SetOrigin(DicomInstanceOrigin::FromWebDav()); |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1289 |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1290 std::string publicId; |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1291 |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1292 try |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1293 { |
4508
8f9090b137f1
Optimization in C-STORE SCP by avoiding an unnecessary DICOM parsing
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4460
diff
changeset
|
1294 context_.Store(publicId, *instance, StoreInstanceMode_Default); |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1295 } |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1296 catch (OrthancException& e) |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1297 { |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1298 if (e.GetErrorCode() == ErrorCode_BadFileFormat) |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1299 { |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1300 LOG(ERROR) << "Cannot import non-DICOM file from ZIP archive: " << filename; |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1301 } |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1302 } |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1303 } |
4244
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1304 } |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1305 |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1306 success = true; |
4240 | 1307 } |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1308 else |
4240 | 1309 { |
4508
8f9090b137f1
Optimization in C-STORE SCP by avoiding an unnecessary DICOM parsing
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4460
diff
changeset
|
1310 std::unique_ptr<DicomInstanceToStore> instance(DicomInstanceToStore::CreateFromBuffer(content)); |
8f9090b137f1
Optimization in C-STORE SCP by avoiding an unnecessary DICOM parsing
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4460
diff
changeset
|
1311 instance->SetOrigin(DicomInstanceOrigin::FromWebDav()); |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1312 |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1313 try |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1314 { |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1315 std::string publicId; |
4796
94616af363ec
added ReceivedCStoreInstanceFilter lua callback + OrthancPluginRegisterIncomingCStoreInstanceFilter in sdk
Alain Mazy <am@osimis.io>
parents:
4697
diff
changeset
|
1316 ServerContext::StoreResult result = context_.Store(publicId, *instance, StoreInstanceMode_Default); |
94616af363ec
added ReceivedCStoreInstanceFilter lua callback + OrthancPluginRegisterIncomingCStoreInstanceFilter in sdk
Alain Mazy <am@osimis.io>
parents:
4697
diff
changeset
|
1317 if (result.GetStatus() == StoreStatus_Success || |
94616af363ec
added ReceivedCStoreInstanceFilter lua callback + OrthancPluginRegisterIncomingCStoreInstanceFilter in sdk
Alain Mazy <am@osimis.io>
parents:
4697
diff
changeset
|
1318 result.GetStatus() == StoreStatus_AlreadyStored) |
4358
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1319 { |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1320 LOG(INFO) << "Successfully imported DICOM instance from WebDAV: " |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1321 << path << " (Orthanc ID: " << publicId << ")"; |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1322 success = true; |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1323 } |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1324 } |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1325 catch (OrthancException& e) |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1326 { |
d6929f052ec4
ZIP archives containing DICOM files can be uploaded using WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4304
diff
changeset
|
1327 } |
4244
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1328 } |
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1329 |
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1330 uploads_.DeleteItem(uri); |
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1331 |
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1332 if (!success) |
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1333 { |
416c35da7d25
robustness against non-dicom files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4243
diff
changeset
|
1334 LOG(WARNING) << "Cannot import DICOM instance from WebWAV (maybe not a DICOM file): " << path; |
4240 | 1335 } |
1336 } | |
1337 } | |
1338 | |
1339 | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1340 OrthancWebDav::INode& OrthancWebDav::GetRootNode(const std::string& rootPath) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1341 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1342 if (rootPath == BY_PATIENTS) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1343 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1344 return *patients_; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1345 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1346 else if (rootPath == BY_STUDIES) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1347 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1348 return *studies_; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1349 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1350 else if (rootPath == BY_DATES) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1351 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1352 return *dates_; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1353 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1354 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1355 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1356 throw OrthancException(ErrorCode_InternalError); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1357 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1358 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1359 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1360 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1361 OrthancWebDav::OrthancWebDav(ServerContext& context, |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1362 bool allowDicomDelete, |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1363 bool allowUpload) : |
4240 | 1364 context_(context), |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1365 allowDicomDelete_(allowDicomDelete), |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1366 allowUpload_(allowUpload), |
4240 | 1367 uploads_(false /* store uploads as temporary files */), |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1368 uploadRunning_(false) |
4240 | 1369 { |
1370 patientsTemplates_[ResourceType_Patient] = "{{PatientID}} - {{PatientName}}"; | |
1371 patientsTemplates_[ResourceType_Study] = "{{StudyDate}} - {{StudyDescription}}"; | |
1372 patientsTemplates_[ResourceType_Series] = "{{Modality}} - {{SeriesDescription}}"; | |
1373 | |
1374 studiesTemplates_[ResourceType_Study] = "{{PatientID}} - {{PatientName}} - {{StudyDescription}}"; | |
1375 studiesTemplates_[ResourceType_Series] = patientsTemplates_[ResourceType_Series]; | |
1376 | |
1377 patients_.reset(new RootNode(context, ResourceType_Patient, patientsTemplates_)); | |
1378 studies_.reset(new RootNode(context, ResourceType_Study, studiesTemplates_)); | |
1379 dates_.reset(new ListOfStudiesByYear(context, studiesTemplates_)); | |
1380 } | |
1381 | |
1382 | |
1383 bool OrthancWebDav::IsExistingFolder(const UriComponents& path) | |
1384 { | |
1385 if (path.empty()) | |
1386 { | |
1387 return true; | |
1388 } | |
1389 else if (path[0] == BY_UIDS) | |
1390 { | |
1391 return (path.size() <= 3 && | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1392 (path.size() != 3 || path[2] != STUDY_INFO)); |
4240 | 1393 } |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1394 else if (path[0] == BY_PATIENTS || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1395 path[0] == BY_STUDIES || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1396 path[0] == BY_DATES) |
4240 | 1397 { |
4252 | 1398 IWebDavBucket::Collection collection; |
1399 return GetRootNode(path[0]).ListCollection(collection, UriComponents(path.begin() + 1, path.end())); | |
4240 | 1400 } |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1401 else if (allowUpload_ && |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1402 path[0] == UPLOADS) |
4240 | 1403 { |
1404 return uploads_.IsExistingFolder(UriComponents(path.begin() + 1, path.end())); | |
1405 } | |
1406 else | |
1407 { | |
1408 return false; | |
1409 } | |
1410 } | |
1411 | |
1412 | |
1413 bool OrthancWebDav::ListCollection(Collection& collection, | |
1414 const UriComponents& path) | |
1415 { | |
1416 if (path.empty()) | |
1417 { | |
4241 | 1418 collection.AddResource(new Folder(BY_DATES)); |
4240 | 1419 collection.AddResource(new Folder(BY_PATIENTS)); |
1420 collection.AddResource(new Folder(BY_STUDIES)); | |
1421 collection.AddResource(new Folder(BY_UIDS)); | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1422 |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1423 if (allowUpload_) |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1424 { |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1425 collection.AddResource(new Folder(UPLOADS)); |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1426 } |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1427 |
4240 | 1428 return true; |
1429 } | |
1430 else if (path[0] == BY_UIDS) | |
1431 { | |
1432 DatabaseLookup query; | |
1433 ResourceType level; | |
1434 size_t limit = 0; // By default, no limits | |
1435 | |
1436 if (path.size() == 1) | |
1437 { | |
1438 level = ResourceType_Study; | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1439 limit = 0; // TODO - Should we limit here? |
4240 | 1440 } |
1441 else if (path.size() == 2) | |
1442 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1443 AddVirtualFile(collection, path, STUDY_INFO); |
4240 | 1444 |
1445 level = ResourceType_Series; | |
1446 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | |
1447 true /* case sensitive */, true /* mandatory tag */); | |
1448 } | |
1449 else if (path.size() == 3) | |
1450 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1451 AddVirtualFile(collection, path, SERIES_INFO); |
4240 | 1452 |
1453 level = ResourceType_Instance; | |
1454 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | |
1455 true /* case sensitive */, true /* mandatory tag */); | |
1456 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], | |
1457 true /* case sensitive */, true /* mandatory tag */); | |
1458 } | |
1459 else | |
1460 { | |
1461 return false; | |
1462 } | |
1463 | |
1464 DicomIdentifiersVisitor visitor(context_, collection, level); | |
1465 context_.Apply(visitor, query, level, 0 /* since */, limit); | |
1466 | |
1467 return true; | |
1468 } | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1469 else if (path[0] == BY_PATIENTS || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1470 path[0] == BY_STUDIES || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1471 path[0] == BY_DATES) |
4240 | 1472 { |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1473 return GetRootNode(path[0]).ListCollection(collection, UriComponents(path.begin() + 1, path.end())); |
4240 | 1474 } |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1475 else if (allowUpload_ && |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1476 path[0] == UPLOADS) |
4240 | 1477 { |
1478 return uploads_.ListCollection(collection, UriComponents(path.begin() + 1, path.end())); | |
1479 } | |
1480 else | |
1481 { | |
1482 return false; | |
1483 } | |
1484 } | |
1485 | |
1486 | |
1487 bool OrthancWebDav::GetFileContent(MimeType& mime, | |
1488 std::string& content, | |
1489 boost::posix_time::ptime& modificationTime, | |
1490 const UriComponents& path) | |
1491 { | |
1492 if (path.empty()) | |
1493 { | |
1494 return false; | |
1495 } | |
1496 else if (path[0] == BY_UIDS) | |
1497 { | |
1498 if (path.size() == 3 && | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1499 path[2] == STUDY_INFO) |
4240 | 1500 { |
1501 DatabaseLookup query; | |
1502 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | |
1503 true /* case sensitive */, true /* mandatory tag */); | |
1504 | |
1505 OrthancJsonVisitor visitor(context_, content, ResourceType_Study); | |
1506 context_.Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */); | |
1507 | |
1508 mime = MimeType_Json; | |
1509 return visitor.IsSuccess(); | |
1510 } | |
1511 else if (path.size() == 4 && | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1512 path[3] == SERIES_INFO) |
4240 | 1513 { |
1514 DatabaseLookup query; | |
1515 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | |
1516 true /* case sensitive */, true /* mandatory tag */); | |
1517 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], | |
1518 true /* case sensitive */, true /* mandatory tag */); | |
1519 | |
1520 OrthancJsonVisitor visitor(context_, content, ResourceType_Series); | |
1521 context_.Apply(visitor, query, ResourceType_Series, 0 /* since */, 0 /* no limit */); | |
1522 | |
1523 mime = MimeType_Json; | |
1524 return visitor.IsSuccess(); | |
1525 } | |
1526 else if (path.size() == 4 && | |
1527 boost::ends_with(path[3], ".dcm")) | |
1528 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1529 const std::string sopInstanceUid = path[3].substr(0, path[3].size() - 4); |
4240 | 1530 |
1531 DatabaseLookup query; | |
1532 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | |
1533 true /* case sensitive */, true /* mandatory tag */); | |
1534 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], | |
1535 true /* case sensitive */, true /* mandatory tag */); | |
1536 query.AddRestConstraint(DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid, | |
1537 true /* case sensitive */, true /* mandatory tag */); | |
1538 | |
1539 DicomFileVisitor visitor(context_, content, modificationTime); | |
1540 context_.Apply(visitor, query, ResourceType_Instance, 0 /* since */, 0 /* no limit */); | |
1541 | |
1542 mime = MimeType_Dicom; | |
1543 return visitor.IsSuccess(); | |
1544 } | |
1545 else | |
1546 { | |
1547 return false; | |
1548 } | |
1549 } | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1550 else if (path[0] == BY_PATIENTS || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1551 path[0] == BY_STUDIES || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1552 path[0] == BY_DATES) |
4240 | 1553 { |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1554 return GetRootNode(path[0]).GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); |
4241 | 1555 } |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1556 else if (allowUpload_ && |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1557 path[0] == UPLOADS) |
4240 | 1558 { |
1559 return uploads_.GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); | |
1560 } | |
1561 else | |
1562 { | |
1563 return false; | |
1564 } | |
1565 } | |
1566 | |
1567 | |
1568 bool OrthancWebDav::StoreFile(const std::string& content, | |
1569 const UriComponents& path) | |
1570 { | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1571 if (allowUpload_ && |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1572 path.size() >= 1 && |
4240 | 1573 path[0] == UPLOADS) |
1574 { | |
1575 UriComponents subpath(UriComponents(path.begin() + 1, path.end())); | |
1576 | |
1577 if (uploads_.StoreFile(content, subpath)) | |
1578 { | |
1579 if (!content.empty()) | |
1580 { | |
1581 uploadQueue_.Enqueue(new SingleValueObject<std::string>(Toolbox::FlattenUri(subpath))); | |
1582 } | |
1583 return true; | |
1584 } | |
1585 else | |
1586 { | |
1587 return false; | |
1588 } | |
1589 } | |
1590 else | |
1591 { | |
1592 return false; | |
1593 } | |
1594 } | |
1595 | |
1596 | |
1597 bool OrthancWebDav::CreateFolder(const UriComponents& path) | |
1598 { | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1599 if (allowUpload_ && |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1600 path.size() >= 1 && |
4240 | 1601 path[0] == UPLOADS) |
1602 { | |
1603 return uploads_.CreateFolder(UriComponents(path.begin() + 1, path.end())); | |
1604 } | |
1605 else | |
1606 { | |
1607 return false; | |
1608 } | |
1609 } | |
1610 | |
1611 | |
1612 bool OrthancWebDav::DeleteItem(const std::vector<std::string>& path) | |
1613 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1614 if (path.empty()) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1615 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1616 return false; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1617 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1618 else if (path[0] == BY_UIDS && |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1619 path.size() >= 2 && |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1620 path.size() <= 4) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1621 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1622 if (allowDicomDelete_) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1623 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1624 ResourceType level; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1625 DatabaseLookup query; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1626 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1627 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1628 true /* case sensitive */, true /* mandatory tag */); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1629 level = ResourceType_Study; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1630 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1631 if (path.size() >= 3) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1632 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1633 if (path[2] == STUDY_INFO) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1634 { |
4252 | 1635 return true; // Allow deletion of virtual files (to avoid blocking recursive DELETE) |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1636 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1637 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1638 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1639 true /* case sensitive */, true /* mandatory tag */); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1640 level = ResourceType_Series; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1641 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1642 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1643 if (path.size() == 4) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1644 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1645 if (path[3] == SERIES_INFO) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1646 { |
4252 | 1647 return true; // Allow deletion of virtual files (to avoid blocking recursive DELETE) |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1648 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1649 else if (boost::ends_with(path[3], ".dcm")) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1650 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1651 const std::string sopInstanceUid = path[3].substr(0, path[3].size() - 4); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1652 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1653 query.AddRestConstraint(DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid, |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1654 true /* case sensitive */, true /* mandatory tag */); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1655 level = ResourceType_Instance; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1656 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1657 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1658 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1659 return false; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1660 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1661 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1662 |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1663 DicomDeleteVisitor visitor(context_, level); |
4252 | 1664 context_.Apply(visitor, query, level, 0 /* since */, 0 /* no limit */); |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1665 return true; |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1666 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1667 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1668 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1669 return false; // read-only |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1670 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1671 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1672 else if (path[0] == BY_PATIENTS || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1673 path[0] == BY_STUDIES || |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1674 path[0] == BY_DATES) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1675 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1676 if (allowDicomDelete_) |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1677 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1678 return GetRootNode(path[0]).DeleteItem(UriComponents(path.begin() + 1, path.end())); |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1679 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1680 else |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1681 { |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1682 return false; // read-only |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1683 } |
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1684 } |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1685 else if (allowUpload_ && |
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1686 path[0] == UPLOADS) |
4240 | 1687 { |
1688 return uploads_.DeleteItem(UriComponents(path.begin() + 1, path.end())); | |
1689 } | |
1690 else | |
1691 { | |
4242
5cfa6ba75dfc
deleting resources from Orthanc WebDAV
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4241
diff
changeset
|
1692 return false; |
4240 | 1693 } |
1694 } | |
1695 | |
1696 | |
1697 void OrthancWebDav::Start() | |
1698 { | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1699 if (uploadRunning_) |
4240 | 1700 { |
1701 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
1702 } | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1703 else if (allowUpload_) |
4240 | 1704 { |
1705 LOG(INFO) << "Starting the WebDAV upload thread"; | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1706 uploadRunning_ = true; |
4240 | 1707 uploadThread_ = boost::thread(UploadWorker, this); |
1708 } | |
1709 } | |
1710 | |
1711 | |
1712 void OrthancWebDav::Stop() | |
1713 { | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1714 if (uploadRunning_) |
4240 | 1715 { |
1716 LOG(INFO) << "Stopping the WebDAV upload thread"; | |
4243
64f57c9d5f79
configuration options for webdav
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4242
diff
changeset
|
1717 uploadRunning_ = false; |
4240 | 1718 if (uploadThread_.joinable()) |
1719 { | |
1720 uploadThread_.join(); | |
1721 } | |
1722 } | |
1723 } | |
1724 } |