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