python-caldav / caldav

Apache License 2.0
314 stars 94 forks source link

Get all calendars returns objects without ids #313

Closed shikasta-net closed 1 year ago

shikasta-net commented 1 year ago

I've just run into this while trying to migrate issues from another task manager to a caldav one.
When I create a calendar on the target server with dav_client.principal().make_calendar, the returned object has an id (whether I specify one or not). But if I try to look up all calendars on the target server with dav_client.principal().calendars() the returned lists of objects all have id=None. The issue is in CalendarSet::calendars where the data from the server doesn't seem to provide an id. This seems weird. I can to try to fix it, I'm just not sure if there's some design reason that it won't be possible.

tobixen commented 1 year ago

I've just run into this while trying to migrate issues from another task manager to a caldav one.

That's interesting, since I'm trying to do task management through my plann project. IMHO, the icalendar standard is not really optimized for task management, I'm doing various workarounds in plann, it would be nice to have a look into other ical-based task managers to see how they get around the limitations.

where the data from the server doesn't seem to provide an id.

The short answer is that the URL itself is the ID - so from that, I don't see any need of changing the code - though if you have any suggestions, I'd like to hear.

There is no well-defined concept of an ID here, and I'm sorry that the caldav library is referring to ID every here and there. Ideally all references should be for "UID" and "URL" and nothing more than that - but I consider backward compatibility to be very important.

There are two standards here, it's CalDAV which is the communication part between the client and the server, and it's the icalendar, the actual calendar data. In CalDAV, every resource is uniquely identified by an URL. In the python library, sometimes "ID" is used as the last part of this URL.

In the icalendar library, every event, journal entry or task has an UID field - so this is the unique identifier in the icalendar context. The python caldav library attempts to map the UID of new events/tasks/journal entries into the URL.

shikasta-net commented 1 year ago

Using the URL to populate the field was my workaround:

  for c in cal_dav_client.calendars():
    c.id = c.canonical_url.split('/')[-2]
    projects[c.id] = c

And what I'm thinking is that could be done inside cal_dav_client.calendars(). This is maybe only an issue when migrating from one URL base to another; I'm trying to keep things simple by copying the already unique IDs for everything but the names had to change, so it then got weird to look up if a Calendar had already been created. I'll see if I can add a minimal change that would populate the ID field from the URL.

tobixen commented 1 year ago

I'll probably merge such a change request, in the caldav library a "calendar ID" seems to already be defined to be the last part of the URL. Anyway, in the long term I think it may be better to remove the Calendar.id field, as it may be confusing. The CalDAV protocol does not have a concept of a "calendar ID", only the calendar URL.

So you're writing a tool for copying the calendar structure from one caldav server to another? Maybe it deserves to be released as a stand-alone tool.

shikasta-net commented 1 year ago

I'm actually migrating from Todoist, which also probably deserves to be documented. It was a somewhat hurried job, but here it is: https://github.com/shikasta-net/todoist_migration

tobixen commented 1 year ago

Sorry for dropping the ball on this one - I've been very busy lately and simply forgot about it.