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