comparison OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp @ 4627:f7d5372b59b3 db-changes

handling revisions of attachments
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 20 Apr 2021 15:11:59 +0200
parents 95ffe3b6ef7c
children 66109d24d26e
comparison
equal deleted inserted replaced
4626:686f189a903d 4627:f7d5372b59b3
1539 .SetDescription("Delete some metadata associated with the given DICOM " + r + 1539 .SetDescription("Delete some metadata associated with the given DICOM " + r +
1540 ". This call will fail if trying to delete a system metadata (i.e. whose index is < 1024).") 1540 ". This call will fail if trying to delete a system metadata (i.e. whose index is < 1024).")
1541 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") 1541 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1542 .SetUriArgument("name", "The name of the metadata, or its index (cf. `UserMetadata` configuration option)") 1542 .SetUriArgument("name", "The name of the metadata, or its index (cf. `UserMetadata` configuration option)")
1543 .SetHttpHeader("If-Match", "Revision of the metadata, to check if its content has not changed and can " 1543 .SetHttpHeader("If-Match", "Revision of the metadata, to check if its content has not changed and can "
1544 "be deleted. This option is mandatory if `CheckRevision` option is `true`."); 1544 "be deleted. This header is mandatory if `CheckRevision` option is `true`.");
1545 return; 1545 return;
1546 } 1546 }
1547 1547
1548 CheckValidResourceType(call); 1548 CheckValidResourceType(call);
1549 const std::string publicId = call.GetUriComponent("id", ""); 1549 const std::string publicId = call.GetUriComponent("id", "");
1684 1684
1685 call.GetOutput().AnswerJson(result); 1685 call.GetOutput().AnswerJson(result);
1686 } 1686 }
1687 1687
1688 1688
1689 static bool GetAttachmentInfo(FileInfo& info, RestApiCall& call) 1689 static void AddAttachmentDocumentation(RestApiGetCall& call,
1690 const std::string& resourceType)
1691 {
1692 call.GetDocumentation()
1693 .SetUriArgument("id", "Orthanc identifier of the " + resourceType + " of interest")
1694 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1695 .SetAnswerHeader("ETag", "Revision of the attachment, to be used in further `PUT` or `DELETE` operations")
1696 .SetHttpHeader("If-None-Match", "Optional revision of the attachment, to check if its content has changed");
1697 }
1698
1699
1700 static bool GetAttachmentInfo(FileInfo& info,
1701 RestApiGetCall& call)
1690 { 1702 {
1691 CheckValidResourceType(call); 1703 CheckValidResourceType(call);
1692 1704
1693 std::string publicId = call.GetUriComponent("id", ""); 1705 const std::string publicId = call.GetUriComponent("id", "");
1694 std::string name = call.GetUriComponent("name", ""); 1706 const std::string name = call.GetUriComponent("name", "");
1695 FileContentType contentType = StringToContentType(name); 1707 FileContentType contentType = StringToContentType(name);
1696 1708
1697 return OrthancRestApi::GetIndex(call).LookupAttachment(info, publicId, contentType); 1709 int64_t revision;
1710 if (OrthancRestApi::GetIndex(call).LookupAttachment(info, revision, publicId, contentType))
1711 {
1712 call.GetOutput().GetLowLevelOutput().
1713 AddHeader("ETag", "\"" + boost::lexical_cast<std::string>(revision) + "\""); // New in Orthanc 1.9.2
1714
1715 int64_t userRevision;
1716 if (GetRevisionHeader(userRevision, call, "If-None-Match") &&
1717 revision == userRevision)
1718 {
1719 call.GetOutput().GetLowLevelOutput().SendStatus(HttpStatus_304_NotModified);
1720 return false;
1721 }
1722 else
1723 {
1724 return true;
1725 }
1726 }
1727 else
1728 {
1729 throw OrthancException(ErrorCode_UnknownResource);
1730 }
1698 } 1731 }
1699 1732
1700 1733
1701 static void GetAttachmentOperations(RestApiGetCall& call) 1734 static void GetAttachmentOperations(RestApiGetCall& call)
1702 { 1735 {
1703 if (call.IsDocumentation()) 1736 if (call.IsDocumentation())
1704 { 1737 {
1705 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); 1738 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
1706 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); 1739 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
1740 AddAttachmentDocumentation(call, r);
1707 call.GetDocumentation() 1741 call.GetDocumentation()
1708 .SetTag("Other") 1742 .SetTag("Other")
1709 .SetSummary("List operations on attachments") 1743 .SetSummary("List operations on attachments")
1710 .SetDescription("Get the list of the operations that are available for attachments associated with the given " + r) 1744 .SetDescription("Get the list of the operations that are available for attachments associated with the given " + r)
1711 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1712 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1713 .AddAnswerType(MimeType_Json, "List of the available operations") 1745 .AddAnswerType(MimeType_Json, "List of the available operations")
1714 .SetHttpGetSample("https://demo.orthanc-server.com/instances/d94d9a03-3003b047-a4affc69-322313b2-680530a2/attachments/dicom", true); 1746 .SetHttpGetSample("https://demo.orthanc-server.com/instances/d94d9a03-3003b047-a4affc69-322313b2-680530a2/attachments/dicom", true);
1715 return; 1747 return;
1716 } 1748 }
1717 1749
1763 .SetSummary("Get attachment" + std::string(uncompress ? "" : " (no decompression)")) 1795 .SetSummary("Get attachment" + std::string(uncompress ? "" : " (no decompression)"))
1764 .SetDescription("Get the (binary) content of one attachment associated with the given " + r + 1796 .SetDescription("Get the (binary) content of one attachment associated with the given " + r +
1765 std::string(uncompress ? "" : ". The attachment will not be decompressed if `StorageCompression` is `true`.")) 1797 std::string(uncompress ? "" : ". The attachment will not be decompressed if `StorageCompression` is `true`."))
1766 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") 1798 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1767 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)") 1799 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1768 .AddAnswerType(MimeType_Binary, "The attachment"); 1800 .AddAnswerType(MimeType_Binary, "The attachment")
1801 .SetAnswerHeader("ETag", "Revision of the attachment, to be used in further `PUT` or `DELETE` operations")
1802 .SetHttpHeader("If-None-Match", "Optional revision of the metadata, to check if its content has changed");
1769 return; 1803 return;
1770 } 1804 }
1771 1805
1772 ServerContext& context = OrthancRestApi::GetContext(call); 1806 ServerContext& context = OrthancRestApi::GetContext(call);
1773 1807
1776 std::string publicId = call.GetUriComponent("id", ""); 1810 std::string publicId = call.GetUriComponent("id", "");
1777 FileContentType type = StringToContentType(call.GetUriComponent("name", "")); 1811 FileContentType type = StringToContentType(call.GetUriComponent("name", ""));
1778 1812
1779 if (uncompress) 1813 if (uncompress)
1780 { 1814 {
1781 context.AnswerAttachment(call.GetOutput(), publicId, type); 1815 FileInfo info;
1816 if (GetAttachmentInfo(info, call))
1817 {
1818 context.AnswerAttachment(call.GetOutput(), publicId, type);
1819 }
1782 } 1820 }
1783 else 1821 else
1784 { 1822 {
1785 // Return the raw data (possibly compressed), as stored on the filesystem 1823 // Return the raw data (possibly compressed), as stored on the filesystem
1786 std::string content; 1824 std::string content;
1787 context.ReadAttachment(content, publicId, type, false); 1825 int64_t revision;
1788 call.GetOutput().AnswerBuffer(content, MimeType_Binary); 1826 context.ReadAttachment(content, revision, publicId, type, false);
1827
1828 call.GetOutput().GetLowLevelOutput().
1829 AddHeader("ETag", "\"" + boost::lexical_cast<std::string>(revision) + "\""); // New in Orthanc 1.9.2
1830
1831 int64_t userRevision;
1832 if (GetRevisionHeader(userRevision, call, "If-None-Match") &&
1833 revision == userRevision)
1834 {
1835 call.GetOutput().GetLowLevelOutput().SendStatus(HttpStatus_304_NotModified);
1836 }
1837 else
1838 {
1839 call.GetOutput().AnswerBuffer(content, MimeType_Binary);
1840 }
1789 } 1841 }
1790 } 1842 }
1791 1843
1792 1844
1793 static void GetAttachmentSize(RestApiGetCall& call) 1845 static void GetAttachmentSize(RestApiGetCall& call)
1794 { 1846 {
1795 if (call.IsDocumentation()) 1847 if (call.IsDocumentation())
1796 { 1848 {
1797 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); 1849 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
1798 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); 1850 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
1851 AddAttachmentDocumentation(call, r);
1799 call.GetDocumentation() 1852 call.GetDocumentation()
1800 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) 1853 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
1801 .SetSummary("Get size of attachment") 1854 .SetSummary("Get size of attachment")
1802 .SetDescription("Get the size of one attachment associated with the given " + r) 1855 .SetDescription("Get the size of one attachment associated with the given " + r)
1803 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1804 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1805 .AddAnswerType(MimeType_PlainText, "The size of the attachment"); 1856 .AddAnswerType(MimeType_PlainText, "The size of the attachment");
1806 return; 1857 return;
1807 } 1858 }
1808 1859
1809 FileInfo info; 1860 FileInfo info;
1818 { 1869 {
1819 if (call.IsDocumentation()) 1870 if (call.IsDocumentation())
1820 { 1871 {
1821 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); 1872 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
1822 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); 1873 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
1874 AddAttachmentDocumentation(call, r);
1823 call.GetDocumentation() 1875 call.GetDocumentation()
1824 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) 1876 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
1825 .SetSummary("Get size of attachment on disk") 1877 .SetSummary("Get size of attachment on disk")
1826 .SetDescription("Get the size of one attachment associated with the given " + r + ", as stored on the disk. " 1878 .SetDescription("Get the size of one attachment associated with the given " + r + ", as stored on the disk. "
1827 "This is different from `.../size` iff `EnableStorage` is `true`.") 1879 "This is different from `.../size` iff `EnableStorage` is `true`.")
1828 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1829 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1830 .AddAnswerType(MimeType_PlainText, "The size of the attachment, as stored on the disk"); 1880 .AddAnswerType(MimeType_PlainText, "The size of the attachment, as stored on the disk");
1831 return; 1881 return;
1832 } 1882 }
1833 1883
1834 FileInfo info; 1884 FileInfo info;
1843 { 1893 {
1844 if (call.IsDocumentation()) 1894 if (call.IsDocumentation())
1845 { 1895 {
1846 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); 1896 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
1847 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); 1897 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
1898 AddAttachmentDocumentation(call, r);
1848 call.GetDocumentation() 1899 call.GetDocumentation()
1849 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) 1900 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
1850 .SetSummary("Get MD5 of attachment") 1901 .SetSummary("Get MD5 of attachment")
1851 .SetDescription("Get the MD5 hash of one attachment associated with the given " + r) 1902 .SetDescription("Get the MD5 hash of one attachment associated with the given " + r)
1852 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1853 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1854 .AddAnswerType(MimeType_PlainText, "The MD5 of the attachment"); 1903 .AddAnswerType(MimeType_PlainText, "The MD5 of the attachment");
1855 return; 1904 return;
1856 } 1905 }
1857 1906
1858 FileInfo info; 1907 FileInfo info;
1868 { 1917 {
1869 if (call.IsDocumentation()) 1918 if (call.IsDocumentation())
1870 { 1919 {
1871 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); 1920 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
1872 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); 1921 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
1922 AddAttachmentDocumentation(call, r);
1873 call.GetDocumentation() 1923 call.GetDocumentation()
1874 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) 1924 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
1875 .SetSummary("Get MD5 of attachment on disk") 1925 .SetSummary("Get MD5 of attachment on disk")
1876 .SetDescription("Get the MD5 hash of one attachment associated with the given " + r + ", as stored on the disk. " 1926 .SetDescription("Get the MD5 hash of one attachment associated with the given " + r + ", as stored on the disk. "
1877 "This is different from `.../md5` iff `EnableStorage` is `true`.") 1927 "This is different from `.../md5` iff `EnableStorage` is `true`.")
1878 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1879 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1880 .AddAnswerType(MimeType_PlainText, "The MD5 of the attachment, as stored on the disk"); 1928 .AddAnswerType(MimeType_PlainText, "The MD5 of the attachment, as stored on the disk");
1881 return; 1929 return;
1882 } 1930 }
1883 1931
1884 FileInfo info; 1932 FileInfo info;
1909 ServerContext& context = OrthancRestApi::GetContext(call); 1957 ServerContext& context = OrthancRestApi::GetContext(call);
1910 CheckValidResourceType(call); 1958 CheckValidResourceType(call);
1911 1959
1912 std::string publicId = call.GetUriComponent("id", ""); 1960 std::string publicId = call.GetUriComponent("id", "");
1913 std::string name = call.GetUriComponent("name", ""); 1961 std::string name = call.GetUriComponent("name", "");
1962 FileContentType contentType = StringToContentType(name);
1914 1963
1915 FileInfo info; 1964 FileInfo info;
1916 if (!GetAttachmentInfo(info, call) || 1965 int64_t revision; // Ignored
1966 if (!OrthancRestApi::GetIndex(call).LookupAttachment(info, revision, publicId, contentType) ||
1917 info.GetCompressedMD5() == "" || 1967 info.GetCompressedMD5() == "" ||
1918 info.GetUncompressedMD5() == "") 1968 info.GetUncompressedMD5() == "")
1919 { 1969 {
1920 // Inexistent resource, or no MD5 available 1970 // Inexistent resource, or no MD5 available
1921 return; 1971 return;
1923 1973
1924 bool ok = false; 1974 bool ok = false;
1925 1975
1926 // First check whether the compressed data is correctly stored in the disk 1976 // First check whether the compressed data is correctly stored in the disk
1927 std::string data; 1977 std::string data;
1928 context.ReadAttachment(data, publicId, StringToContentType(name), false); 1978 context.ReadAttachment(data, revision, publicId, StringToContentType(name), false);
1929 1979
1930 std::string actualMD5; 1980 std::string actualMD5;
1931 Toolbox::ComputeMD5(actualMD5, data); 1981 Toolbox::ComputeMD5(actualMD5, data);
1932 1982
1933 if (actualMD5 == info.GetCompressedMD5()) 1983 if (actualMD5 == info.GetCompressedMD5())
1938 { 1988 {
1939 ok = true; 1989 ok = true;
1940 } 1990 }
1941 else 1991 else
1942 { 1992 {
1943 context.ReadAttachment(data, publicId, StringToContentType(name), true); 1993 context.ReadAttachment(data, revision, publicId, StringToContentType(name), true);
1944 Toolbox::ComputeMD5(actualMD5, data); 1994 Toolbox::ComputeMD5(actualMD5, data);
1945 ok = (actualMD5 == info.GetUncompressedMD5()); 1995 ok = (actualMD5 == info.GetUncompressedMD5());
1946 } 1996 }
1947 } 1997 }
1948 1998
1970 .SetDescription("Attach a file to the given DICOM " + r + 2020 .SetDescription("Attach a file to the given DICOM " + r +
1971 ". This call will fail if trying to modify a system attachment (i.e. whose index is < 1024).") 2021 ". This call will fail if trying to modify a system attachment (i.e. whose index is < 1024).")
1972 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") 2022 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
1973 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)") 2023 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
1974 .AddRequestType(MimeType_Binary, "Binary data containing the attachment") 2024 .AddRequestType(MimeType_Binary, "Binary data containing the attachment")
1975 .AddAnswerType(MimeType_Json, "Empty JSON object in the case of a success"); 2025 .AddAnswerType(MimeType_Json, "Empty JSON object in the case of a success")
2026 .SetHttpHeader("If-Match", "Revision of the attachment, if this is not the first time this attachment is set.");
1976 return; 2027 return;
1977 } 2028 }
1978 2029
1979 ServerContext& context = OrthancRestApi::GetContext(call); 2030 ServerContext& context = OrthancRestApi::GetContext(call);
1980 CheckValidResourceType(call); 2031 CheckValidResourceType(call);
1981 2032
1982 std::string publicId = call.GetUriComponent("id", ""); 2033 std::string publicId = call.GetUriComponent("id", "");
1983 std::string name = call.GetUriComponent("name", ""); 2034 std::string name = call.GetUriComponent("name", "");
1984 2035
1985 FileContentType contentType = StringToContentType(name); 2036 FileContentType contentType = StringToContentType(name);
1986 if (IsUserContentType(contentType) && // It is forbidden to modify internal attachments 2037 if (IsUserContentType(contentType)) // It is forbidden to modify internal attachments
1987 context.AddAttachment(publicId, StringToContentType(name), call.GetBodyData(), call.GetBodySize())) 2038 {
1988 { 2039 int64_t oldRevision;
2040 bool hasOldRevision = GetRevisionHeader(oldRevision, call, "if-match");
2041
2042 if (!hasOldRevision)
2043 {
2044 OrthancConfiguration::ReaderLock lock;
2045 if (lock.GetConfiguration().GetBooleanParameter(CHECK_REVISIONS, false))
2046 {
2047 // "StatelessDatabaseOperations::AddAttachment()" will ignore
2048 // the actual value of "oldRevision" if the metadata is
2049 // inexistent as expected
2050 hasOldRevision = true;
2051 oldRevision = -1; // dummy value
2052 }
2053 }
2054
2055 int64_t newRevision;
2056 context.AddAttachment(newRevision, publicId, StringToContentType(name), call.GetBodyData(),
2057 call.GetBodySize(), hasOldRevision, oldRevision);
2058
2059 call.GetOutput().GetLowLevelOutput().
2060 AddHeader("ETag", "\"" + boost::lexical_cast<std::string>(newRevision) + "\""); // New in Orthanc 1.9.2
2061
1989 call.GetOutput().AnswerBuffer("{}", MimeType_Json); 2062 call.GetOutput().AnswerBuffer("{}", MimeType_Json);
1990 } 2063 }
1991 else 2064 else
1992 { 2065 {
1993 call.GetOutput().SignalError(HttpStatus_403_Forbidden); 2066 call.GetOutput().SignalError(HttpStatus_403_Forbidden);
2005 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) 2078 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
2006 .SetSummary("Delete attachment") 2079 .SetSummary("Delete attachment")
2007 .SetDescription("Delete an attachment associated with the given DICOM " + r + 2080 .SetDescription("Delete an attachment associated with the given DICOM " + r +
2008 ". This call will fail if trying to delete a system attachment (i.e. whose index is < 1024).") 2081 ". This call will fail if trying to delete a system attachment (i.e. whose index is < 1024).")
2009 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") 2082 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
2010 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)"); 2083 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
2084 .SetHttpHeader("If-Match", "Revision of the attachment, to check if its content has not changed and can "
2085 "be deleted. This header is mandatory if `CheckRevision` option is `true`.");
2011 return; 2086 return;
2012 } 2087 }
2013 2088
2014 CheckValidResourceType(call); 2089 CheckValidResourceType(call);
2015 2090
2040 } 2115 }
2041 } 2116 }
2042 2117
2043 if (allowed) 2118 if (allowed)
2044 { 2119 {
2045 OrthancRestApi::GetIndex(call).DeleteAttachment(publicId, contentType); 2120 bool found;
2046 call.GetOutput().AnswerBuffer("{}", MimeType_Json); 2121 int64_t revision;
2122 if (GetRevisionHeader(revision, call, "if-match"))
2123 {
2124 found = OrthancRestApi::GetIndex(call).DeleteAttachment(publicId, contentType, true, revision);
2125 }
2126 else
2127 {
2128 OrthancConfiguration::ReaderLock lock;
2129 if (lock.GetConfiguration().GetBooleanParameter(CHECK_REVISIONS, false))
2130 {
2131 throw OrthancException(ErrorCode_Revision,
2132 "HTTP header \"If-Match\" is missing, as \"CheckRevision\" is \"true\"");
2133 }
2134 else
2135 {
2136 found = OrthancRestApi::GetIndex(call).DeleteAttachment(publicId, contentType, false, -1 /* dummy value */);
2137 }
2138 }
2139
2140 if (found)
2141 {
2142 call.GetOutput().AnswerBuffer("", MimeType_PlainText);
2143 }
2144 else
2145 {
2146 throw OrthancException(ErrorCode_UnknownResource);
2147 }
2047 } 2148 }
2048 else 2149 else
2049 { 2150 {
2050 call.GetOutput().SignalError(HttpStatus_403_Forbidden); 2151 call.GetOutput().SignalError(HttpStatus_403_Forbidden);
2051 } 2152 }
2083 { 2184 {
2084 if (call.IsDocumentation()) 2185 if (call.IsDocumentation())
2085 { 2186 {
2086 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); 2187 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
2087 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); 2188 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
2189 AddAttachmentDocumentation(call, r);
2088 call.GetDocumentation() 2190 call.GetDocumentation()
2089 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) 2191 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
2090 .SetSummary("Is attachment compressed?") 2192 .SetSummary("Is attachment compressed?")
2091 .SetDescription("Test whether the attachment has been stored as a compressed file on the disk.") 2193 .SetDescription("Test whether the attachment has been stored as a compressed file on the disk.")
2092 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
2093 .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)")
2094 .AddAnswerType(MimeType_PlainText, "`0` if the attachment was stored uncompressed, `1` if it was compressed"); 2194 .AddAnswerType(MimeType_PlainText, "`0` if the attachment was stored uncompressed, `1` if it was compressed");
2095 return; 2195 return;
2096 } 2196 }
2097 2197
2098 FileInfo info; 2198 FileInfo info;
2884 index.GetChildInstances(instances, *study); 2984 index.GetChildInstances(instances, *study);
2885 2985
2886 for (std::list<std::string>::const_iterator 2986 for (std::list<std::string>::const_iterator
2887 instance = instances.begin(); instance != instances.end(); ++instance) 2987 instance = instances.begin(); instance != instances.end(); ++instance)
2888 { 2988 {
2889 index.DeleteAttachment(*instance, FileContentType_DicomAsJson); 2989 index.DeleteAttachment(*instance, FileContentType_DicomAsJson, false /* no revision checks */, -1 /* dummy */);
2890 } 2990 }
2891 } 2991 }
2892 2992
2893 call.GetOutput().AnswerBuffer("", MimeType_PlainText); 2993 call.GetOutput().AnswerBuffer("", MimeType_PlainText);
2894 } 2994 }