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