delete.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. # This file is part of Radicale - CalDAV and CardDAV server
  2. # Copyright © 2008 Nicolas Kandel
  3. # Copyright © 2008 Pascal Halter
  4. # Copyright © 2008-2017 Guillaume Ayoub
  5. # Copyright © 2017-2018 Unrud <unrud@outlook.com>
  6. # Copyright © 2024-2024 Peter Bieringer <pb@bieringer.de>
  7. #
  8. # This library is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This library is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  20. import xml.etree.ElementTree as ET
  21. from http import client
  22. from typing import Optional
  23. from radicale import httputils, storage, types, xmlutils
  24. from radicale.app.base import Access, ApplicationBase
  25. from radicale.hook import HookNotificationItem, HookNotificationItemTypes
  26. def xml_delete(base_prefix: str, path: str, collection: storage.BaseCollection,
  27. item_href: Optional[str] = None) -> ET.Element:
  28. """Read and answer DELETE requests.
  29. Read rfc4918-9.6 for info.
  30. """
  31. collection.delete(item_href)
  32. multistatus = ET.Element(xmlutils.make_clark("D:multistatus"))
  33. response = ET.Element(xmlutils.make_clark("D:response"))
  34. multistatus.append(response)
  35. href_element = ET.Element(xmlutils.make_clark("D:href"))
  36. href_element.text = xmlutils.make_href(base_prefix, path)
  37. response.append(href_element)
  38. status = ET.Element(xmlutils.make_clark("D:status"))
  39. status.text = xmlutils.make_response(200)
  40. response.append(status)
  41. return multistatus
  42. class ApplicationPartDelete(ApplicationBase):
  43. def do_DELETE(self, environ: types.WSGIEnviron, base_prefix: str,
  44. path: str, user: str) -> types.WSGIResponse:
  45. """Manage DELETE request."""
  46. access = Access(self._rights, user, path)
  47. if not access.check("w"):
  48. return httputils.NOT_ALLOWED
  49. with self._storage.acquire_lock("w", user):
  50. item = next(iter(self._storage.discover(path)), None)
  51. if not item:
  52. return httputils.NOT_FOUND
  53. if not access.check("w", item):
  54. return httputils.NOT_ALLOWED
  55. if_match = environ.get("HTTP_IF_MATCH", "*")
  56. if if_match not in ("*", item.etag):
  57. # ETag precondition not verified, do not delete item
  58. return httputils.PRECONDITION_FAILED
  59. hook_notification_item_list = []
  60. if isinstance(item, storage.BaseCollection):
  61. if self._permit_delete_collection:
  62. for i in item.get_all():
  63. hook_notification_item_list.append(
  64. HookNotificationItem(
  65. HookNotificationItemTypes.DELETE,
  66. access.path,
  67. i.uid
  68. )
  69. )
  70. xml_answer = xml_delete(base_prefix, path, item)
  71. else:
  72. return httputils.NOT_ALLOWED
  73. else:
  74. assert item.collection is not None
  75. assert item.href is not None
  76. hook_notification_item_list.append(
  77. HookNotificationItem(
  78. HookNotificationItemTypes.DELETE,
  79. access.path,
  80. item.uid
  81. )
  82. )
  83. xml_answer = xml_delete(
  84. base_prefix, path, item.collection, item.href)
  85. for notification_item in hook_notification_item_list:
  86. self._hook.notify(notification_item)
  87. headers = {"Content-Type": "text/xml; charset=%s" % self._encoding}
  88. return client.OK, headers, self._xml_response(xml_answer)