Mercurial > hg > orthanc
comparison OrthancServer/Sources/OrthancWebDav.cpp @ 4242:5cfa6ba75dfc
deleting resources from Orthanc WebDAV
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 09 Oct 2020 17:51:06 +0200 |
parents | 3510da0e260c |
children | 64f57c9d5f79 |
comparison
equal
deleted
inserted
replaced
4241:3510da0e260c | 4242:5cfa6ba75dfc |
---|---|
47 static const char* const BY_STUDIES = "by-studies"; | 47 static const char* const BY_STUDIES = "by-studies"; |
48 static const char* const BY_DATES = "by-dates"; | 48 static const char* const BY_DATES = "by-dates"; |
49 static const char* const BY_UIDS = "by-uids"; | 49 static const char* const BY_UIDS = "by-uids"; |
50 static const char* const UPLOADS = "uploads"; | 50 static const char* const UPLOADS = "uploads"; |
51 static const char* const MAIN_DICOM_TAGS = "MainDicomTags"; | 51 static const char* const MAIN_DICOM_TAGS = "MainDicomTags"; |
52 static const char* const STUDY_INFO = "study.json"; | |
53 static const char* const SERIES_INFO = "series.json"; | |
52 | 54 |
53 | 55 |
54 namespace Orthanc | 56 namespace Orthanc |
55 { | 57 { |
56 static boost::posix_time::ptime GetNow() | 58 static boost::posix_time::ptime GetNow() |
455 { | 457 { |
456 private: | 458 private: |
457 ServerContext& context_; | 459 ServerContext& context_; |
458 std::string parentSeries_; | 460 std::string parentSeries_; |
459 | 461 |
462 static bool LookupInstanceId(std::string& instanceId, | |
463 const UriComponents& path) | |
464 { | |
465 if (path.size() == 1 && | |
466 boost::ends_with(path[0], ".dcm")) | |
467 { | |
468 instanceId = path[0].substr(0, path[0].size() - 4); | |
469 return true; | |
470 } | |
471 else | |
472 { | |
473 return false; | |
474 } | |
475 } | |
476 | |
460 public: | 477 public: |
461 InstancesOfSeries(ServerContext& context, | 478 InstancesOfSeries(ServerContext& context, |
462 const std::string& parentSeries) : | 479 const std::string& parentSeries) : |
463 context_(context), | 480 context_(context), |
464 parentSeries_(parentSeries) | 481 parentSeries_(parentSeries) |
509 virtual bool GetFileContent(MimeType& mime, | 526 virtual bool GetFileContent(MimeType& mime, |
510 std::string& content, | 527 std::string& content, |
511 boost::posix_time::ptime& time, | 528 boost::posix_time::ptime& time, |
512 const UriComponents& path) ORTHANC_OVERRIDE | 529 const UriComponents& path) ORTHANC_OVERRIDE |
513 { | 530 { |
514 if (path.size() == 1 && | 531 std::string instanceId; |
515 boost::ends_with(path[0], ".dcm")) | 532 if (LookupInstanceId(instanceId, path)) |
516 { | 533 { |
517 std::string instanceId = path[0].substr(0, path[0].size() - 4); | |
518 | |
519 try | 534 try |
520 { | 535 { |
521 mime = MimeType_Dicom; | 536 mime = MimeType_Dicom; |
522 context_.ReadDicom(content, instanceId); | 537 context_.ReadDicom(content, instanceId); |
523 LookupTime(time, context_, instanceId, MetadataType_Instance_ReceptionDate); | 538 LookupTime(time, context_, instanceId, MetadataType_Instance_ReceptionDate); |
526 catch (OrthancException&) | 541 catch (OrthancException&) |
527 { | 542 { |
528 // File was removed | 543 // File was removed |
529 return false; | 544 return false; |
530 } | 545 } |
546 } | |
547 else | |
548 { | |
549 return false; | |
550 } | |
551 } | |
552 | |
553 virtual bool DeleteItem(const UriComponents& path) ORTHANC_OVERRIDE | |
554 { | |
555 std::string instanceId; | |
556 if (LookupInstanceId(instanceId, path)) | |
557 { | |
558 Json::Value info; | |
559 return context_.DeleteResource(info, instanceId, ResourceType_Instance); | |
531 } | 560 } |
532 else | 561 else |
533 { | 562 { |
534 return false; | 563 return false; |
535 } | 564 } |
555 INode* GetChild(const std::string& path) // Don't delete the result pointer! | 584 INode* GetChild(const std::string& path) // Don't delete the result pointer! |
556 { | 585 { |
557 Children::const_iterator child = children_.find(path); | 586 Children::const_iterator child = children_.find(path); |
558 if (child == children_.end()) | 587 if (child == children_.end()) |
559 { | 588 { |
560 INode* child = CreateChild(path); | 589 INode* child = CreateSubfolder(path); |
561 | 590 |
562 if (child == NULL) | 591 if (child == NULL) |
563 { | 592 { |
564 return NULL; | 593 return NULL; |
565 } | 594 } |
575 return child->second; | 604 return child->second; |
576 } | 605 } |
577 } | 606 } |
578 | 607 |
579 protected: | 608 protected: |
580 void RemoveSubfolder(const std::string& path) | 609 void InvalidateSubfolder(const std::string& path) |
581 { | 610 { |
582 Children::iterator child = children_.find(path); | 611 Children::iterator child = children_.find(path); |
583 if (child != children_.end()) | 612 if (child != children_.end()) |
584 { | 613 { |
585 assert(child->second != NULL); | 614 assert(child->second != NULL); |
589 } | 618 } |
590 | 619 |
591 virtual void Refresh() = 0; | 620 virtual void Refresh() = 0; |
592 | 621 |
593 virtual bool ListSubfolders(IWebDavBucket::Collection& target) = 0; | 622 virtual bool ListSubfolders(IWebDavBucket::Collection& target) = 0; |
594 | 623 |
595 virtual INode* CreateChild(const std::string& path) = 0; | 624 virtual INode* CreateSubfolder(const std::string& path) = 0; |
596 | 625 |
597 public: | 626 public: |
598 virtual ~InternalNode() | 627 virtual ~InternalNode() |
599 { | 628 { |
600 for (Children::iterator it = children_.begin(); it != children_.end(); ++it) | 629 for (Children::iterator it = children_.begin(); it != children_.end(); ++it) |
618 { | 647 { |
619 // Recursivity | 648 // Recursivity |
620 INode* child = GetChild(path[0]); | 649 INode* child = GetChild(path[0]); |
621 if (child == NULL) | 650 if (child == NULL) |
622 { | 651 { |
623 return false; | 652 // Must be "true" to allow DELETE on folders that are |
653 // automatically removed through recursive deletion | |
654 return true; | |
624 } | 655 } |
625 else | 656 else |
626 { | 657 { |
627 UriComponents subpath(path.begin() + 1, path.end()); | 658 UriComponents subpath(path.begin() + 1, path.end()); |
628 return child->ListCollection(target, subpath); | 659 return child->ListCollection(target, subpath); |
655 UriComponents subpath(path.begin() + 1, path.end()); | 686 UriComponents subpath(path.begin() + 1, path.end()); |
656 return child->GetFileContent(mime, content, time, subpath); | 687 return child->GetFileContent(mime, content, time, subpath); |
657 } | 688 } |
658 } | 689 } |
659 } | 690 } |
691 | |
692 | |
693 virtual bool DeleteItem(const UriComponents& path) ORTHANC_OVERRIDE ORTHANC_FINAL | |
694 { | |
695 Refresh(); | |
696 | |
697 if (path.empty()) | |
698 { | |
699 IWebDavBucket::Collection tmp; | |
700 if (ListSubfolders(tmp)) | |
701 { | |
702 return (tmp.GetSize() == 0); | |
703 } | |
704 else | |
705 { | |
706 return false; | |
707 } | |
708 } | |
709 else | |
710 { | |
711 INode* child = GetChild(path[0]); | |
712 if (child == NULL) | |
713 { | |
714 return true; | |
715 } | |
716 else | |
717 { | |
718 // Recursivity | |
719 UriComponents subpath(path.begin() + 1, path.end()); | |
720 return child->DeleteItem(subpath); | |
721 } | |
722 } | |
723 } | |
660 }; | 724 }; |
661 | 725 |
662 | 726 |
663 class OrthancWebDav::ListOfResources : public InternalNode | 727 class OrthancWebDav::ListOfResources : public InternalNode |
664 { | 728 { |
679 | 743 |
680 // Remove the children whose associated resource doesn't exist anymore | 744 // Remove the children whose associated resource doesn't exist anymore |
681 for (std::set<std::string>::const_iterator | 745 for (std::set<std::string>::const_iterator |
682 it = removedPaths.begin(); it != removedPaths.end(); ++it) | 746 it = removedPaths.begin(); it != removedPaths.end(); ++it) |
683 { | 747 { |
684 RemoveSubfolder(*it); | 748 InvalidateSubfolder(*it); |
685 } | 749 } |
686 } | 750 } |
687 | 751 |
688 virtual bool ListSubfolders(IWebDavBucket::Collection& target) ORTHANC_OVERRIDE ORTHANC_FINAL | 752 virtual bool ListSubfolders(IWebDavBucket::Collection& target) ORTHANC_OVERRIDE ORTHANC_FINAL |
689 { | 753 { |
708 | 772 |
709 return true; | 773 return true; |
710 } | 774 } |
711 } | 775 } |
712 | 776 |
713 virtual INode* CreateChild(const std::string& path) ORTHANC_OVERRIDE ORTHANC_FINAL | 777 virtual INode* CreateSubfolder(const std::string& path) ORTHANC_OVERRIDE ORTHANC_FINAL |
714 { | 778 { |
715 ResourcesIndex::Map::const_iterator resource = index_->GetPathToResource().find(path); | 779 ResourcesIndex::Map::const_iterator resource = index_->GetPathToResource().find(path); |
716 if (resource == index_->GetPathToResource().end()) | 780 if (resource == index_->GetPathToResource().end()) |
717 { | 781 { |
718 return NULL; | 782 return NULL; |
725 | 789 |
726 ServerContext& GetContext() const | 790 ServerContext& GetContext() const |
727 { | 791 { |
728 return context_; | 792 return context_; |
729 } | 793 } |
730 | 794 |
731 virtual void GetCurrentResources(std::list<std::string>& resources) = 0; | 795 virtual void GetCurrentResources(std::list<std::string>& resources) = 0; |
732 | 796 |
733 virtual INode* CreateResourceNode(const std::string& resource) = 0; | 797 virtual INode* CreateResourceNode(const std::string& resource) = 0; |
734 | 798 |
735 public: | 799 public: |
929 { | 993 { |
930 private: | 994 private: |
931 std::set<std::string> months_; | 995 std::set<std::string> months_; |
932 | 996 |
933 public: | 997 public: |
934 Visitor() | |
935 { | |
936 } | |
937 | |
938 const std::set<std::string>& GetMonths() const | 998 const std::set<std::string>& GetMonths() const |
939 { | 999 { |
940 return months_; | 1000 return months_; |
941 } | 1001 } |
942 | 1002 |
984 } | 1044 } |
985 | 1045 |
986 return true; | 1046 return true; |
987 } | 1047 } |
988 | 1048 |
989 virtual INode* CreateChild(const std::string& path) ORTHANC_OVERRIDE | 1049 virtual INode* CreateSubfolder(const std::string& path) ORTHANC_OVERRIDE |
990 { | 1050 { |
991 if (path.size() != 7) // Format: "YYYY-MM" | 1051 if (path.size() != 7) // Format: "YYYY-MM" |
992 { | 1052 { |
993 throw OrthancException(ErrorCode_InternalError); | 1053 throw OrthancException(ErrorCode_InternalError); |
994 } | 1054 } |
1052 } | 1112 } |
1053 | 1113 |
1054 return true; | 1114 return true; |
1055 } | 1115 } |
1056 | 1116 |
1057 virtual INode* CreateChild(const std::string& path) ORTHANC_OVERRIDE | 1117 virtual INode* CreateSubfolder(const std::string& path) ORTHANC_OVERRIDE |
1058 { | 1118 { |
1059 return new ListOfStudiesByMonth(context_, path, templates_); | 1119 return new ListOfStudiesByMonth(context_, path, templates_); |
1060 } | 1120 } |
1061 | 1121 |
1062 public: | 1122 public: |
1067 { | 1127 { |
1068 } | 1128 } |
1069 }; | 1129 }; |
1070 | 1130 |
1071 | 1131 |
1132 class OrthancWebDav::DicomDeleteVisitor : public ServerContext::ILookupVisitor | |
1133 { | |
1134 private: | |
1135 ServerContext& context_; | |
1136 ResourceType level_; | |
1137 | |
1138 public: | |
1139 DicomDeleteVisitor(ServerContext& context, | |
1140 ResourceType level) : | |
1141 context_(context), | |
1142 level_(level) | |
1143 { | |
1144 } | |
1145 | |
1146 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE | |
1147 { | |
1148 return false; // (*) | |
1149 } | |
1150 | |
1151 virtual void MarkAsComplete() ORTHANC_OVERRIDE | |
1152 { | |
1153 } | |
1154 | |
1155 virtual void Visit(const std::string& publicId, | |
1156 const std::string& instanceId /* unused */, | |
1157 const DicomMap& mainDicomTags /* unused */, | |
1158 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE | |
1159 { | |
1160 Json::Value info; | |
1161 context_.DeleteResource(info, publicId, level_); | |
1162 } | |
1163 }; | |
1164 | |
1165 | |
1072 void OrthancWebDav::AddVirtualFile(Collection& collection, | 1166 void OrthancWebDav::AddVirtualFile(Collection& collection, |
1073 const UriComponents& path, | 1167 const UriComponents& path, |
1074 const std::string& filename) | 1168 const std::string& filename) |
1075 { | 1169 { |
1076 MimeType mime; | 1170 MimeType mime; |
1146 } | 1240 } |
1147 } | 1241 } |
1148 } | 1242 } |
1149 | 1243 |
1150 | 1244 |
1151 OrthancWebDav::OrthancWebDav(ServerContext& context) : | 1245 OrthancWebDav::INode& OrthancWebDav::GetRootNode(const std::string& rootPath) |
1246 { | |
1247 if (rootPath == BY_PATIENTS) | |
1248 { | |
1249 return *patients_; | |
1250 } | |
1251 else if (rootPath == BY_STUDIES) | |
1252 { | |
1253 return *studies_; | |
1254 } | |
1255 else if (rootPath == BY_DATES) | |
1256 { | |
1257 return *dates_; | |
1258 } | |
1259 else | |
1260 { | |
1261 throw OrthancException(ErrorCode_InternalError); | |
1262 } | |
1263 } | |
1264 | |
1265 | |
1266 OrthancWebDav::OrthancWebDav(ServerContext& context, | |
1267 bool allowDicomDelete) : | |
1152 context_(context), | 1268 context_(context), |
1269 allowDicomDelete_(allowDicomDelete), | |
1153 uploads_(false /* store uploads as temporary files */), | 1270 uploads_(false /* store uploads as temporary files */), |
1154 running_(false) | 1271 running_(false) |
1155 { | 1272 { |
1156 patientsTemplates_[ResourceType_Patient] = "{{PatientID}} - {{PatientName}}"; | 1273 patientsTemplates_[ResourceType_Patient] = "{{PatientID}} - {{PatientName}}"; |
1157 patientsTemplates_[ResourceType_Study] = "{{StudyDate}} - {{StudyDescription}}"; | 1274 patientsTemplates_[ResourceType_Study] = "{{StudyDate}} - {{StudyDescription}}"; |
1173 return true; | 1290 return true; |
1174 } | 1291 } |
1175 else if (path[0] == BY_UIDS) | 1292 else if (path[0] == BY_UIDS) |
1176 { | 1293 { |
1177 return (path.size() <= 3 && | 1294 return (path.size() <= 3 && |
1178 (path.size() != 3 || path[2] != "study.json")); | 1295 (path.size() != 3 || path[2] != STUDY_INFO)); |
1179 } | 1296 } |
1180 else if (path[0] == BY_PATIENTS) | 1297 else if (path[0] == BY_PATIENTS || |
1298 path[0] == BY_STUDIES || | |
1299 path[0] == BY_DATES) | |
1181 { | 1300 { |
1182 IWebDavBucket::Collection tmp; | 1301 IWebDavBucket::Collection tmp; |
1183 return patients_->ListCollection(tmp, UriComponents(path.begin() + 1, path.end())); | 1302 return GetRootNode(path[0]).ListCollection(tmp, UriComponents(path.begin() + 1, path.end())); |
1184 } | |
1185 else if (path[0] == BY_STUDIES) | |
1186 { | |
1187 IWebDavBucket::Collection tmp; | |
1188 return studies_->ListCollection(tmp, UriComponents(path.begin() + 1, path.end())); | |
1189 } | |
1190 else if (path[0] == BY_DATES) | |
1191 { | |
1192 IWebDavBucket::Collection tmp; | |
1193 return dates_->ListCollection(tmp, UriComponents(path.begin() + 1, path.end())); | |
1194 } | 1303 } |
1195 else if (path[0] == UPLOADS) | 1304 else if (path[0] == UPLOADS) |
1196 { | 1305 { |
1197 return uploads_.IsExistingFolder(UriComponents(path.begin() + 1, path.end())); | 1306 return uploads_.IsExistingFolder(UriComponents(path.begin() + 1, path.end())); |
1198 } | 1307 } |
1226 level = ResourceType_Study; | 1335 level = ResourceType_Study; |
1227 limit = 100; // TODO | 1336 limit = 100; // TODO |
1228 } | 1337 } |
1229 else if (path.size() == 2) | 1338 else if (path.size() == 2) |
1230 { | 1339 { |
1231 AddVirtualFile(collection, path, "study.json"); | 1340 AddVirtualFile(collection, path, STUDY_INFO); |
1232 | 1341 |
1233 level = ResourceType_Series; | 1342 level = ResourceType_Series; |
1234 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | 1343 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], |
1235 true /* case sensitive */, true /* mandatory tag */); | 1344 true /* case sensitive */, true /* mandatory tag */); |
1236 } | 1345 } |
1237 else if (path.size() == 3) | 1346 else if (path.size() == 3) |
1238 { | 1347 { |
1239 AddVirtualFile(collection, path, "series.json"); | 1348 AddVirtualFile(collection, path, SERIES_INFO); |
1240 | 1349 |
1241 level = ResourceType_Instance; | 1350 level = ResourceType_Instance; |
1242 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | 1351 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], |
1243 true /* case sensitive */, true /* mandatory tag */); | 1352 true /* case sensitive */, true /* mandatory tag */); |
1244 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], | 1353 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], |
1252 DicomIdentifiersVisitor visitor(context_, collection, level); | 1361 DicomIdentifiersVisitor visitor(context_, collection, level); |
1253 context_.Apply(visitor, query, level, 0 /* since */, limit); | 1362 context_.Apply(visitor, query, level, 0 /* since */, limit); |
1254 | 1363 |
1255 return true; | 1364 return true; |
1256 } | 1365 } |
1257 else if (path[0] == BY_PATIENTS) | 1366 else if (path[0] == BY_PATIENTS || |
1258 { | 1367 path[0] == BY_STUDIES || |
1259 return patients_->ListCollection(collection, UriComponents(path.begin() + 1, path.end())); | 1368 path[0] == BY_DATES) |
1260 } | 1369 { |
1261 else if (path[0] == BY_STUDIES) | 1370 return GetRootNode(path[0]).ListCollection(collection, UriComponents(path.begin() + 1, path.end())); |
1262 { | |
1263 return studies_->ListCollection(collection, UriComponents(path.begin() + 1, path.end())); | |
1264 } | |
1265 else if (path[0] == BY_DATES) | |
1266 { | |
1267 return dates_->ListCollection(collection, UriComponents(path.begin() + 1, path.end())); | |
1268 } | 1371 } |
1269 else if (path[0] == UPLOADS) | 1372 else if (path[0] == UPLOADS) |
1270 { | 1373 { |
1271 return uploads_.ListCollection(collection, UriComponents(path.begin() + 1, path.end())); | 1374 return uploads_.ListCollection(collection, UriComponents(path.begin() + 1, path.end())); |
1272 } | 1375 } |
1287 return false; | 1390 return false; |
1288 } | 1391 } |
1289 else if (path[0] == BY_UIDS) | 1392 else if (path[0] == BY_UIDS) |
1290 { | 1393 { |
1291 if (path.size() == 3 && | 1394 if (path.size() == 3 && |
1292 path[2] == "study.json") | 1395 path[2] == STUDY_INFO) |
1293 { | 1396 { |
1294 DatabaseLookup query; | 1397 DatabaseLookup query; |
1295 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | 1398 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], |
1296 true /* case sensitive */, true /* mandatory tag */); | 1399 true /* case sensitive */, true /* mandatory tag */); |
1297 | 1400 |
1300 | 1403 |
1301 mime = MimeType_Json; | 1404 mime = MimeType_Json; |
1302 return visitor.IsSuccess(); | 1405 return visitor.IsSuccess(); |
1303 } | 1406 } |
1304 else if (path.size() == 4 && | 1407 else if (path.size() == 4 && |
1305 path[3] == "series.json") | 1408 path[3] == SERIES_INFO) |
1306 { | 1409 { |
1307 DatabaseLookup query; | 1410 DatabaseLookup query; |
1308 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | 1411 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], |
1309 true /* case sensitive */, true /* mandatory tag */); | 1412 true /* case sensitive */, true /* mandatory tag */); |
1310 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], | 1413 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], |
1317 return visitor.IsSuccess(); | 1420 return visitor.IsSuccess(); |
1318 } | 1421 } |
1319 else if (path.size() == 4 && | 1422 else if (path.size() == 4 && |
1320 boost::ends_with(path[3], ".dcm")) | 1423 boost::ends_with(path[3], ".dcm")) |
1321 { | 1424 { |
1322 std::string sopInstanceUid = path[3]; | 1425 const std::string sopInstanceUid = path[3].substr(0, path[3].size() - 4); |
1323 sopInstanceUid.resize(sopInstanceUid.size() - 4); | |
1324 | 1426 |
1325 DatabaseLookup query; | 1427 DatabaseLookup query; |
1326 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | 1428 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], |
1327 true /* case sensitive */, true /* mandatory tag */); | 1429 true /* case sensitive */, true /* mandatory tag */); |
1328 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], | 1430 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], |
1339 else | 1441 else |
1340 { | 1442 { |
1341 return false; | 1443 return false; |
1342 } | 1444 } |
1343 } | 1445 } |
1344 else if (path[0] == BY_PATIENTS) | 1446 else if (path[0] == BY_PATIENTS || |
1345 { | 1447 path[0] == BY_STUDIES || |
1346 return patients_->GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); | 1448 path[0] == BY_DATES) |
1347 } | 1449 { |
1348 else if (path[0] == BY_STUDIES) | 1450 return GetRootNode(path[0]).GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); |
1349 { | |
1350 return studies_->GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); | |
1351 } | |
1352 else if (path[0] == BY_DATES) | |
1353 { | |
1354 return dates_->GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); | |
1355 } | 1451 } |
1356 else if (path[0] == UPLOADS) | 1452 else if (path[0] == UPLOADS) |
1357 { | 1453 { |
1358 return uploads_.GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); | 1454 return uploads_.GetFileContent(mime, content, modificationTime, UriComponents(path.begin() + 1, path.end())); |
1359 } | 1455 } |
1406 } | 1502 } |
1407 | 1503 |
1408 | 1504 |
1409 bool OrthancWebDav::DeleteItem(const std::vector<std::string>& path) | 1505 bool OrthancWebDav::DeleteItem(const std::vector<std::string>& path) |
1410 { | 1506 { |
1411 if (path.size() >= 1 && | 1507 if (path.empty()) |
1412 path[0] == UPLOADS) | 1508 { |
1509 return false; | |
1510 } | |
1511 else if (path[0] == BY_UIDS && | |
1512 path.size() >= 2 && | |
1513 path.size() <= 4) | |
1514 { | |
1515 if (allowDicomDelete_) | |
1516 { | |
1517 ResourceType level; | |
1518 DatabaseLookup query; | |
1519 | |
1520 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], | |
1521 true /* case sensitive */, true /* mandatory tag */); | |
1522 level = ResourceType_Study; | |
1523 | |
1524 if (path.size() >= 3) | |
1525 { | |
1526 if (path[2] == STUDY_INFO) | |
1527 { | |
1528 return true; // Allow deletion of virtual files | |
1529 } | |
1530 | |
1531 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], | |
1532 true /* case sensitive */, true /* mandatory tag */); | |
1533 level = ResourceType_Series; | |
1534 } | |
1535 | |
1536 if (path.size() == 4) | |
1537 { | |
1538 if (path[3] == SERIES_INFO) | |
1539 { | |
1540 return true; // Allow deletion of virtual files | |
1541 } | |
1542 else if (boost::ends_with(path[3], ".dcm")) | |
1543 { | |
1544 const std::string sopInstanceUid = path[3].substr(0, path[3].size() - 4); | |
1545 | |
1546 query.AddRestConstraint(DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid, | |
1547 true /* case sensitive */, true /* mandatory tag */); | |
1548 level = ResourceType_Instance; | |
1549 } | |
1550 else | |
1551 { | |
1552 return false; | |
1553 } | |
1554 } | |
1555 | |
1556 std::cout << "\n\n" << query.Format() << "\n\n"; | |
1557 | |
1558 DicomDeleteVisitor visitor(context_, level); | |
1559 context_.Apply(visitor, query, ResourceType_Instance, 0 /* since */, 0 /* no limit */); | |
1560 return true; | |
1561 } | |
1562 else | |
1563 { | |
1564 return false; // read-only | |
1565 } | |
1566 } | |
1567 else if (path[0] == BY_PATIENTS || | |
1568 path[0] == BY_STUDIES || | |
1569 path[0] == BY_DATES) | |
1570 { | |
1571 if (allowDicomDelete_) | |
1572 { | |
1573 return GetRootNode(path[0]).DeleteItem(UriComponents(path.begin() + 1, path.end())); | |
1574 } | |
1575 else | |
1576 { | |
1577 return false; // read-only | |
1578 } | |
1579 } | |
1580 else if (path[0] == UPLOADS) | |
1413 { | 1581 { |
1414 return uploads_.DeleteItem(UriComponents(path.begin() + 1, path.end())); | 1582 return uploads_.DeleteItem(UriComponents(path.begin() + 1, path.end())); |
1415 } | 1583 } |
1416 else | 1584 else |
1417 { | 1585 { |
1418 return false; // read-only | 1586 return false; |
1419 } | 1587 } |
1420 } | 1588 } |
1421 | 1589 |
1422 | 1590 |
1423 void OrthancWebDav::Start() | 1591 void OrthancWebDav::Start() |