comparison OrthancServer/Sources/OrthancWebDav.cpp @ 5809:023a99146dd0 attach-custom-data

merged find-refactoring -> attach-custom-data
author Alain Mazy <am@orthanc.team>
date Tue, 24 Sep 2024 12:53:43 +0200
parents d851a54e49b7
children 593e110de3d8
comparison
equal deleted inserted replaced
5808:63c025cf6958 5809:023a99146dd0
26 #include "../../OrthancFramework/Sources/Compression/ZipReader.h" 26 #include "../../OrthancFramework/Sources/Compression/ZipReader.h"
27 #include "../../OrthancFramework/Sources/DicomFormat/DicomArray.h" 27 #include "../../OrthancFramework/Sources/DicomFormat/DicomArray.h"
28 #include "../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" 28 #include "../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h"
29 #include "../../OrthancFramework/Sources/HttpServer/WebDavStorage.h" 29 #include "../../OrthancFramework/Sources/HttpServer/WebDavStorage.h"
30 #include "../../OrthancFramework/Sources/Logging.h" 30 #include "../../OrthancFramework/Sources/Logging.h"
31 #include "ResourceFinder.h"
31 #include "Search/DatabaseLookup.h" 32 #include "Search/DatabaseLookup.h"
32 #include "ServerContext.h" 33 #include "ServerContext.h"
33 34
34 #include <boost/regex.hpp> 35 #include <boost/regex.hpp>
35 #include <boost/algorithm/string/predicate.hpp> 36 #include <boost/algorithm/string/predicate.hpp>
48 { 49 {
49 static boost::posix_time::ptime GetNow() 50 static boost::posix_time::ptime GetNow()
50 { 51 {
51 return boost::posix_time::second_clock::universal_time(); 52 return boost::posix_time::second_clock::universal_time();
52 } 53 }
54
55
56 static void ParseTime(boost::posix_time::ptime& target,
57 const std::string& value)
58 {
59 try
60 {
61 target = boost::posix_time::from_iso_string(value);
62 }
63 catch (std::exception& e)
64 {
65 target = GetNow();
66 }
67 }
53 68
54 69
55 static void LookupTime(boost::posix_time::ptime& target, 70 static void LookupTime(boost::posix_time::ptime& target,
56 ServerContext& context, 71 ServerContext& context,
57 const std::string& publicId, 72 const std::string& publicId,
60 { 75 {
61 std::string value; 76 std::string value;
62 int64_t revision; // Ignored 77 int64_t revision; // Ignored
63 if (context.GetIndex().LookupMetadata(value, revision, publicId, level, metadata)) 78 if (context.GetIndex().LookupMetadata(value, revision, publicId, level, metadata))
64 { 79 {
65 try 80 ParseTime(target, value);
66 { 81 }
67 target = boost::posix_time::from_iso_string(value); 82 else
68 return; 83 {
69 } 84 target = GetNow();
70 catch (std::exception& e) 85 }
71 {
72 }
73 }
74
75 target = GetNow();
76 } 86 }
77 87
78 88
79 class OrthancWebDav::DicomIdentifiersVisitor : public ServerContext::ILookupVisitor 89 class OrthancWebDav::DicomIdentifiersVisitor : public ServerContext::ILookupVisitor
80 { 90 {
167 } 177 }
168 } 178 }
169 }; 179 };
170 180
171 181
182 class OrthancWebDav::DicomIdentifiersVisitorV2 : public ResourceFinder::IVisitor
183 {
184 private:
185 bool isComplete_;
186 Collection& target_;
187
188 public:
189 explicit DicomIdentifiersVisitorV2(Collection& target) :
190 isComplete_(false),
191 target_(target)
192 {
193 }
194
195 virtual void MarkAsComplete() ORTHANC_OVERRIDE
196 {
197 isComplete_ = true; // TODO
198 }
199
200 virtual void Apply(const FindResponse::Resource& resource,
201 const DicomMap& requestedTags) ORTHANC_OVERRIDE
202 {
203 DicomMap resourceTags;
204 resource.GetMainDicomTags(resourceTags, resource.GetLevel());
205
206 std::string uid;
207 bool hasUid;
208
209 std::string time;
210 bool hasTime;
211
212 switch (resource.GetLevel())
213 {
214 case ResourceType_Study:
215 hasUid = resourceTags.LookupStringValue(uid, DICOM_TAG_STUDY_INSTANCE_UID, false);
216 hasTime = resource.LookupMetadata(time, resource.GetLevel(), MetadataType_LastUpdate);
217 break;
218
219 case ResourceType_Series:
220 hasUid = resourceTags.LookupStringValue(uid, DICOM_TAG_SERIES_INSTANCE_UID, false);
221 hasTime = resource.LookupMetadata(time, resource.GetLevel(), MetadataType_LastUpdate);
222 break;
223
224 case ResourceType_Instance:
225 hasUid = resourceTags.LookupStringValue(uid, DICOM_TAG_SOP_INSTANCE_UID, false);
226 hasTime = resource.LookupMetadata(time, resource.GetLevel(), MetadataType_Instance_ReceptionDate);
227 break;
228
229 default:
230 throw OrthancException(ErrorCode_InternalError);
231 }
232
233 if (hasUid &&
234 !uid.empty())
235 {
236 std::unique_ptr<Resource> item;
237
238 if (resource.GetLevel() == ResourceType_Instance)
239 {
240 FileInfo info;
241 if (resource.LookupAttachment(info, FileContentType_Dicom))
242 {
243 std::unique_ptr<File> f(new File(uid + ".dcm"));
244 f->SetMimeType(MimeType_Dicom);
245 f->SetContentLength(info.GetUncompressedSize());
246 item.reset(f.release());
247 }
248 }
249 else
250 {
251 item.reset(new Folder(uid));
252 }
253
254 if (item.get() != NULL)
255 {
256 if (hasTime)
257 {
258 boost::posix_time::ptime t;
259 ParseTime(t, time);
260 item->SetCreationTime(t);
261 }
262 else
263 {
264 item->SetCreationTime(GetNow());
265 }
266
267 target_.AddResource(item.release());
268 }
269 }
270 }
271 };
272
273
172 class OrthancWebDav::DicomFileVisitor : public ServerContext::ILookupVisitor 274 class OrthancWebDav::DicomFileVisitor : public ServerContext::ILookupVisitor
173 { 275 {
174 private: 276 private:
175 ServerContext& context_; 277 ServerContext& context_;
176 bool success_; 278 bool success_;
218 success_ = true; 320 success_ = true;
219 } 321 }
220 } 322 }
221 }; 323 };
222 324
325
326 class OrthancWebDav::DicomFileVisitorV2 : public ResourceFinder::IVisitor
327 {
328 private:
329 ServerContext& context_;
330 bool success_;
331 std::string& target_;
332 boost::posix_time::ptime& time_;
333
334 public:
335 DicomFileVisitorV2(ServerContext& context,
336 std::string& target,
337 boost::posix_time::ptime& time) :
338 context_(context),
339 success_(false),
340 target_(target),
341 time_(time)
342 {
343 }
344
345 bool IsSuccess() const
346 {
347 return success_;
348 }
349
350 virtual void MarkAsComplete() ORTHANC_OVERRIDE
351 {
352 }
353
354 virtual void Apply(const FindResponse::Resource& resource,
355 const DicomMap& requestedTags) ORTHANC_OVERRIDE
356 {
357 if (success_)
358 {
359 success_ = false; // Two matches => Error
360 }
361 else
362 {
363 std::string s;
364 if (resource.LookupMetadata(s, ResourceType_Instance, MetadataType_Instance_ReceptionDate))
365 {
366 ParseTime(time_, s);
367 }
368 else
369 {
370 time_ = GetNow();
371 }
372
373 context_.ReadDicom(target_, resource.GetIdentifier());
374 success_ = true;
375 }
376 }
377 };
378
223 379
224 class OrthancWebDav::OrthancJsonVisitor : public ServerContext::ILookupVisitor 380 class OrthancWebDav::OrthancJsonVisitor : public ServerContext::ILookupVisitor
225 { 381 {
226 private: 382 private:
227 ServerContext& context_; 383 ServerContext& context_;
953 { 1109 {
954 private: 1110 private:
955 std::string year_; 1111 std::string year_;
956 std::string month_; 1112 std::string month_;
957 1113
958 class Visitor : public ServerContext::ILookupVisitor 1114 class Visitor : public ResourceFinder::IVisitor
959 { 1115 {
960 private: 1116 private:
961 std::list<std::string>& resources_; 1117 std::list<std::string>& resources_;
962 1118
963 public: 1119 public:
964 explicit Visitor(std::list<std::string>& resources) : 1120 explicit Visitor(std::list<std::string>& resources) :
965 resources_(resources) 1121 resources_(resources)
966 { 1122 {
967 } 1123 }
968 1124
969 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE
970 {
971 return false; // (*)
972 }
973
974 virtual void MarkAsComplete() ORTHANC_OVERRIDE 1125 virtual void MarkAsComplete() ORTHANC_OVERRIDE
975 { 1126 {
976 } 1127 }
977 1128
978 virtual void Visit(const std::string& publicId, 1129 virtual void Apply(const FindResponse::Resource& resource,
979 const std::string& instanceId /* unused */, 1130 const DicomMap& requestedTags) ORTHANC_OVERRIDE
980 const DicomMap& mainDicomTags, 1131 {
981 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE 1132 resources_.push_back(resource.GetIdentifier());
982 {
983 resources_.push_back(publicId);
984 } 1133 }
985 }; 1134 };
986 1135
987 protected: 1136 protected:
988 virtual void GetCurrentResources(std::list<std::string>& resources) ORTHANC_OVERRIDE 1137 virtual void GetCurrentResources(std::list<std::string>& resources) ORTHANC_OVERRIDE
990 DatabaseLookup query; 1139 DatabaseLookup query;
991 query.AddRestConstraint(DICOM_TAG_STUDY_DATE, year_ + month_ + "01-" + year_ + month_ + "31", 1140 query.AddRestConstraint(DICOM_TAG_STUDY_DATE, year_ + month_ + "01-" + year_ + month_ + "31",
992 true /* case sensitive */, true /* mandatory tag */); 1141 true /* case sensitive */, true /* mandatory tag */);
993 1142
994 Visitor visitor(resources); 1143 Visitor visitor(resources);
995 GetContext().Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */); 1144
1145 ResourceFinder finder(ResourceType_Study, false /* no expand */);
1146 finder.SetDatabaseLookup(query);
1147 finder.Execute(visitor, GetContext());
996 } 1148 }
997 1149
998 virtual INode* CreateResourceNode(const std::string& resource) ORTHANC_OVERRIDE 1150 virtual INode* CreateResourceNode(const std::string& resource) ORTHANC_OVERRIDE
999 { 1151 {
1000 return new SingleDicomResource(GetContext(), ResourceType_Series, resource, GetTemplates()); 1152 return new SingleDicomResource(GetContext(), ResourceType_Series, resource, GetTemplates());
1023 private: 1175 private:
1024 ServerContext& context_; 1176 ServerContext& context_;
1025 std::string year_; 1177 std::string year_;
1026 const Templates& templates_; 1178 const Templates& templates_;
1027 1179
1028 class Visitor : public ServerContext::ILookupVisitor 1180 class Visitor : public ResourceFinder::IVisitor
1029 { 1181 {
1030 private: 1182 private:
1031 std::set<std::string> months_; 1183 std::set<std::string> months_;
1032 1184
1033 public: 1185 public:
1034 const std::set<std::string>& GetMonths() const 1186 const std::set<std::string>& GetMonths() const
1035 { 1187 {
1036 return months_; 1188 return months_;
1037 } 1189 }
1038 1190
1039 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE
1040 {
1041 return false; // (*)
1042 }
1043
1044 virtual void MarkAsComplete() ORTHANC_OVERRIDE 1191 virtual void MarkAsComplete() ORTHANC_OVERRIDE
1045 { 1192 {
1046 } 1193 }
1047 1194
1048 virtual void Visit(const std::string& publicId, 1195 virtual void Apply(const FindResponse::Resource& resource,
1049 const std::string& instanceId /* unused */, 1196 const DicomMap& requestedTags) ORTHANC_OVERRIDE
1050 const DicomMap& mainDicomTags, 1197 {
1051 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE 1198 DicomMap mainDicomTags;
1052 { 1199 resource.GetMainDicomTags(mainDicomTags, ResourceType_Study);
1200
1053 std::string s; 1201 std::string s;
1054 if (mainDicomTags.LookupStringValue(s, DICOM_TAG_STUDY_DATE, false) && 1202 if (mainDicomTags.LookupStringValue(s, DICOM_TAG_STUDY_DATE, false) &&
1055 s.size() == 8) 1203 s.size() == 8)
1056 { 1204 {
1057 months_.insert(s.substr(4, 2)); // Get the month from "YYYYMMDD" 1205 months_.insert(s.substr(4, 2)); // Get the month from "YYYYMMDD"
1069 DatabaseLookup query; 1217 DatabaseLookup query;
1070 query.AddRestConstraint(DICOM_TAG_STUDY_DATE, year_ + "0101-" + year_ + "1231", 1218 query.AddRestConstraint(DICOM_TAG_STUDY_DATE, year_ + "0101-" + year_ + "1231",
1071 true /* case sensitive */, true /* mandatory tag */); 1219 true /* case sensitive */, true /* mandatory tag */);
1072 1220
1073 Visitor visitor; 1221 Visitor visitor;
1074 context_.Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */); 1222
1223 ResourceFinder finder(ResourceType_Study, false /* no expand */);
1224 finder.SetDatabaseLookup(query);
1225 finder.Execute(visitor, context_);
1075 1226
1076 for (std::set<std::string>::const_iterator it = visitor.GetMonths().begin(); 1227 for (std::set<std::string>::const_iterator it = visitor.GetMonths().begin();
1077 it != visitor.GetMonths().end(); ++it) 1228 it != visitor.GetMonths().end(); ++it)
1078 { 1229 {
1079 target.AddResource(new IWebDavBucket::Folder(year_ + "-" + *it)); 1230 target.AddResource(new IWebDavBucket::Folder(year_ + "-" + *it));
1163 { 1314 {
1164 } 1315 }
1165 }; 1316 };
1166 1317
1167 1318
1168 class OrthancWebDav::DicomDeleteVisitor : public ServerContext::ILookupVisitor 1319 class OrthancWebDav::DicomDeleteVisitor : public ResourceFinder::IVisitor
1169 { 1320 {
1170 private: 1321 private:
1171 ServerContext& context_; 1322 ServerContext& context_;
1172 ResourceType level_; 1323 ResourceType level_;
1173 1324
1177 context_(context), 1328 context_(context),
1178 level_(level) 1329 level_(level)
1179 { 1330 {
1180 } 1331 }
1181 1332
1182 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE
1183 {
1184 return false; // (*)
1185 }
1186
1187 virtual void MarkAsComplete() ORTHANC_OVERRIDE 1333 virtual void MarkAsComplete() ORTHANC_OVERRIDE
1188 { 1334 {
1189 } 1335 }
1190 1336
1191 virtual void Visit(const std::string& publicId, 1337 virtual void Apply(const FindResponse::Resource& resource,
1192 const std::string& instanceId /* unused */, 1338 const DicomMap& requestedTags) ORTHANC_OVERRIDE
1193 const DicomMap& mainDicomTags /* unused */,
1194 const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE
1195 { 1339 {
1196 Json::Value info; 1340 Json::Value info;
1197 context_.DeleteResource(info, publicId, level_); 1341 context_.DeleteResource(info, resource.GetIdentifier(), level_);
1198 } 1342 }
1199 }; 1343 };
1200 1344
1201 1345
1202 void OrthancWebDav::AddVirtualFile(Collection& collection, 1346 void OrthancWebDav::AddVirtualFile(Collection& collection,
1453 else 1597 else
1454 { 1598 {
1455 return false; 1599 return false;
1456 } 1600 }
1457 1601
1458 DicomIdentifiersVisitor visitor(context_, collection, level); 1602 if (true)
1459 context_.Apply(visitor, query, level, 0 /* since */, limit); 1603 {
1460 1604 /**
1605 * EXPERIMENTAL VERSION
1606 **/
1607
1608 ResourceFinder finder(level, false /* don't expand */);
1609 finder.SetDatabaseLookup(query);
1610 finder.SetRetrieveMetadata(true);
1611
1612 switch (level)
1613 {
1614 case ResourceType_Study:
1615 finder.AddRequestedTag(DICOM_TAG_STUDY_INSTANCE_UID);
1616 break;
1617
1618 case ResourceType_Series:
1619 finder.AddRequestedTag(DICOM_TAG_SERIES_INSTANCE_UID);
1620 break;
1621
1622 case ResourceType_Instance:
1623 finder.AddRequestedTag(DICOM_TAG_SOP_INSTANCE_UID);
1624 finder.SetRetrieveAttachments(true);
1625 break;
1626
1627 default:
1628 throw OrthancException(ErrorCode_InternalError);
1629 }
1630
1631 DicomIdentifiersVisitorV2 visitor(collection);
1632 finder.Execute(visitor, context_);
1633 }
1634 else
1635 {
1636 /**
1637 * VERSION IN ORTHANC <= 1.12.4
1638 **/
1639
1640 DicomIdentifiersVisitor visitor(context_, collection, level);
1641 context_.Apply(visitor, query, level, 0 /* since */, limit);
1642 }
1643
1461 return true; 1644 return true;
1462 } 1645 }
1463 else if (path[0] == BY_PATIENTS || 1646 else if (path[0] == BY_PATIENTS ||
1464 path[0] == BY_STUDIES || 1647 path[0] == BY_STUDIES ||
1465 path[0] == BY_DATES) 1648 path[0] == BY_DATES)
1476 return false; 1659 return false;
1477 } 1660 }
1478 } 1661 }
1479 1662
1480 1663
1664 static bool GetOrthancJson(std::string& target,
1665 ServerContext& context,
1666 ResourceType level,
1667 const DatabaseLookup& query)
1668 {
1669 ResourceFinder finder(level, true /* expand */);
1670 finder.SetDatabaseLookup(query);
1671
1672 Json::Value expanded;
1673 finder.Execute(expanded, context, DicomToJsonFormat_Human, false /* don't add "Metadata" */);
1674
1675 if (expanded.size() != 1)
1676 {
1677 return false;
1678 }
1679 else
1680 {
1681 target = expanded[0].toStyledString();
1682
1683 // Replace UNIX newlines with DOS newlines
1684 boost::replace_all(target, "\n", "\r\n");
1685
1686 return true;
1687 }
1688 }
1689
1690
1481 bool OrthancWebDav::GetFileContent(MimeType& mime, 1691 bool OrthancWebDav::GetFileContent(MimeType& mime,
1482 std::string& content, 1692 std::string& content,
1483 boost::posix_time::ptime& modificationTime, 1693 boost::posix_time::ptime& modificationTime,
1484 const UriComponents& path) 1694 const UriComponents& path)
1485 { 1695 {
1493 path[2] == STUDY_INFO) 1703 path[2] == STUDY_INFO)
1494 { 1704 {
1495 DatabaseLookup query; 1705 DatabaseLookup query;
1496 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], 1706 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1],
1497 true /* case sensitive */, true /* mandatory tag */); 1707 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 1708
1502 mime = MimeType_Json; 1709 mime = MimeType_Json;
1503 return visitor.IsSuccess(); 1710
1711 if (true)
1712 {
1713 /**
1714 * EXPERIMENTAL VERSION
1715 **/
1716 return GetOrthancJson(content, context_, ResourceType_Study, query);
1717 }
1718 else
1719 {
1720 /**
1721 * VERSION IN ORTHANC <= 1.12.4
1722 **/
1723 OrthancJsonVisitor visitor(context_, content, ResourceType_Study);
1724 context_.Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */);
1725 return visitor.IsSuccess();
1726 }
1504 } 1727 }
1505 else if (path.size() == 4 && 1728 else if (path.size() == 4 &&
1506 path[3] == SERIES_INFO) 1729 path[3] == SERIES_INFO)
1507 { 1730 {
1508 DatabaseLookup query; 1731 DatabaseLookup query;
1509 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1], 1732 query.AddRestConstraint(DICOM_TAG_STUDY_INSTANCE_UID, path[1],
1510 true /* case sensitive */, true /* mandatory tag */); 1733 true /* case sensitive */, true /* mandatory tag */);
1511 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], 1734 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2],
1512 true /* case sensitive */, true /* mandatory tag */); 1735 true /* case sensitive */, true /* mandatory tag */);
1513 1736
1514 OrthancJsonVisitor visitor(context_, content, ResourceType_Series);
1515 context_.Apply(visitor, query, ResourceType_Series, 0 /* since */, 0 /* no limit */);
1516
1517 mime = MimeType_Json; 1737 mime = MimeType_Json;
1518 return visitor.IsSuccess(); 1738
1739 if (true)
1740 {
1741 /**
1742 * EXPERIMENTAL VERSION
1743 **/
1744 return GetOrthancJson(content, context_, ResourceType_Series, query);
1745 }
1746 else
1747 {
1748 /**
1749 * VERSION IN ORTHANC <= 1.12.4
1750 **/
1751 OrthancJsonVisitor visitor(context_, content, ResourceType_Series);
1752 context_.Apply(visitor, query, ResourceType_Series, 0 /* since */, 0 /* no limit */);
1753 return visitor.IsSuccess();
1754 }
1519 } 1755 }
1520 else if (path.size() == 4 && 1756 else if (path.size() == 4 &&
1521 boost::ends_with(path[3], ".dcm")) 1757 boost::ends_with(path[3], ".dcm"))
1522 { 1758 {
1523 const std::string sopInstanceUid = path[3].substr(0, path[3].size() - 4); 1759 const std::string sopInstanceUid = path[3].substr(0, path[3].size() - 4);
1528 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2], 1764 query.AddRestConstraint(DICOM_TAG_SERIES_INSTANCE_UID, path[2],
1529 true /* case sensitive */, true /* mandatory tag */); 1765 true /* case sensitive */, true /* mandatory tag */);
1530 query.AddRestConstraint(DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid, 1766 query.AddRestConstraint(DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid,
1531 true /* case sensitive */, true /* mandatory tag */); 1767 true /* case sensitive */, true /* mandatory tag */);
1532 1768
1533 DicomFileVisitor visitor(context_, content, modificationTime);
1534 context_.Apply(visitor, query, ResourceType_Instance, 0 /* since */, 0 /* no limit */);
1535
1536 mime = MimeType_Dicom; 1769 mime = MimeType_Dicom;
1537 return visitor.IsSuccess(); 1770
1771 if (true)
1772 {
1773 /**
1774 * EXPERIMENTAL VERSION
1775 **/
1776 ResourceFinder finder(ResourceType_Instance, false /* no expand */);
1777 finder.SetDatabaseLookup(query);
1778 finder.SetRetrieveMetadata(true);
1779 finder.SetRetrieveAttachments(true);
1780
1781 DicomFileVisitorV2 visitor(context_, content, modificationTime);
1782 finder.Execute(visitor, context_);
1783
1784 return visitor.IsSuccess();
1785 }
1786 else
1787 {
1788 /**
1789 * VERSION IN ORTHANC <= 1.12.4
1790 **/
1791 DicomFileVisitor visitor(context_, content, modificationTime);
1792 context_.Apply(visitor, query, ResourceType_Instance, 0 /* since */, 0 /* no limit */);
1793 return visitor.IsSuccess();
1794 }
1538 } 1795 }
1539 else 1796 else
1540 { 1797 {
1541 return false; 1798 return false;
1542 } 1799 }
1653 return false; 1910 return false;
1654 } 1911 }
1655 } 1912 }
1656 1913
1657 DicomDeleteVisitor visitor(context_, level); 1914 DicomDeleteVisitor visitor(context_, level);
1658 context_.Apply(visitor, query, level, 0 /* since */, 0 /* no limit */); 1915
1916 ResourceFinder finder(level, false /* no expand */);
1917 finder.SetDatabaseLookup(query);
1918 finder.Execute(visitor, context_);
1659 return true; 1919 return true;
1660 } 1920 }
1661 else 1921 else
1662 { 1922 {
1663 return false; // read-only 1923 return false; // read-only