python-caldav / caldav

Apache License 2.0
313 stars 91 forks source link

Nextcloud/ SabreDav fails to delete calendar event due to trashbin #371

Closed nkay08 closed 6 months ago

nkay08 commented 6 months ago

Good day and thank you for this nice python module. I have been using it for some time and recently I encountered some errors when trying to delete some events.

DEBUG:urllib3.connectionpool:https://<calendar_host> "DELETE /<calendar_url>/040000008200E00074C5B7101A82E00800000000B03915CCC856D7010000000000000000100000002142D65A21874149BDEF6742718D881F2024-01-05%2010%3A00%3A00%2B00%3A00.ics HTTP/1.1" 403 None
ERROR:root:AuthorizationError at 'https://<calendar_url>/040000008200E00074C5B7101A82E00800000000B03915CCC856D7010000000000000000100000002142D65A21874149BDEF6742718D881F2024-01-05%2010%3A00%3A00%2B00%3A00.ics', reason Forbidden

I logged the response content and it contains this:

<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\Forbidden</s:exception>
  <s:message>A calendar object with URI 040000008200E00074C5B7101A82E00800000000B03915CCC856D7010000000000000000100000002142D65A21874149BDEF6742718D881F2024-01-05 10:00:00+00:00-deleted.ics already exists in calendar 23, therefore this object can't be moved into the trashbin</s:message>
</d:error>

This issue seems to occur when an event with the same UID had been created, delete and created again. I am getting the UID from an external source and need to delete and recreate some events from time to time.
Nextcloud seems to have enabled a trashbin for calendar events, which creates another event with <url>-deleted.ics url.

Steps to reproduce:


EDIT: An oversight on my part: The nextcloud calendar UI has a "Trash Bin" button which can also be cleared.

There is probably no changes needed for this module.

tobixen commented 6 months ago

Sorry for the late reply on this one.

This is a server side problem as far as I can tell. Now if you can redo the steps using other client software without getting problems, then we may consider to do research on why it doesn't work with the python caldav library, and I may have a hunch ... with caldav, every calendar item has two identifiers - the URL and the uid. While the server sets the first part of the URL, it's the client side deciding the filename upon creating the event or task. In the python caldav library, the filename is decided based on the uid of the event. Perhaps if you put another event with the same uid but another url it would work.

The logic for setting the URL is in generate_url. You may try to replace quote(self.id.replace("/", "%2F")) + ".ics" with f"{uuid.uuid1()}.ics" and see if that helps. However, I don't feel easy changing this logic. To me it seems obvious that an event with the same UID should have the same URL, plus I'm scared that such a change will cause people telling me some few months/years down the line that things have stopped working for them.

tobixen commented 6 months ago

Edit: seeing that the problem is that the server will report conflicts and duplicated uid with a <url>-deleted.ics, then my suggestion above obviously won't help at all. What you could try to do from the client side would be something like Event(url=old_url.replace('.ics', '-deleted.ics', client=davclient).delete() and see if that helps.

I'm also fairly convinced that the library should not be changed to support this rather narrow use-case scenario for one particular server implementation, so I will press the "close" button. However, if someone finds it really important, then a solution would possibly be to catch the error, search for a <url>-deleted.ics thingy, see if it can be deleted, and then retry the save.