Mercurial > hg > orthanc
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 } |