diff --git a/homeassistant/components/caldav/coordinator.py b/homeassistant/components/caldav/coordinator.py index 3c9940c073d..4b4f37a8f01 100644 --- a/homeassistant/components/caldav/coordinator.py +++ b/homeassistant/components/caldav/coordinator.py @@ -79,6 +79,12 @@ class CalDavUpdateCoordinator(DataUpdateCoordinator[CalendarEvent | None]): end=self.to_local(self.get_end_date(vevent)), location=get_attr_value(vevent, "location"), description=get_attr_value(vevent, "description"), + uid=get_attr_value(vevent, "uid"), + recurrence_id=( + str(v) + if (v := get_attr_value(vevent, "recurrence_id")) is not None + else None + ), ) ) @@ -175,6 +181,12 @@ class CalDavUpdateCoordinator(DataUpdateCoordinator[CalendarEvent | None]): end=self.to_local(self.get_end_date(vevent)), location=get_attr_value(vevent, "location"), description=get_attr_value(vevent, "description"), + uid=get_attr_value(vevent, "uid"), + recurrence_id=( + str(v) + if (v := get_attr_value(vevent, "recurrence_id")) is not None + else None + ), ) @staticmethod diff --git a/tests/components/caldav/test_calendar.py b/tests/components/caldav/test_calendar.py index e9523989b10..9e0768e061f 100644 --- a/tests/components/caldav/test_calendar.py +++ b/tests/components/caldav/test_calendar.py @@ -5,7 +5,7 @@ import datetime from http import HTTPStatus import logging from typing import Any -from unittest.mock import MagicMock, Mock +from unittest.mock import MagicMock, Mock, patch import zoneinfo from caldav.objects import Event @@ -1065,13 +1065,67 @@ async def test_get_events_custom_calendars( "summary": "This is a normal event", "location": "Hamburg", "description": "Surprisingly rainy", - "uid": None, + "uid": "0", "recurrence_id": None, "rrule": None, } ] +async def test_get_events_with_recurrence_id( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, +) -> None: + """Test that uid and recurrence_id are populated from VEVENT data.""" + vevent_with_recurrence_id = """BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//E-Corp.//CalDAV Client//EN +BEGIN:VEVENT +UID:original-event-uid +RECURRENCE-ID:20171127T170000Z +DTSTAMP:20171125T000000Z +DTSTART:20171127T180000Z +DTEND:20171127T190000Z +SUMMARY:Modified occurrence +LOCATION:Hamburg +DESCRIPTION:This occurrence was moved +END:VEVENT +END:VCALENDAR""" + calendar = Mock() + calendar.name = "Example" + calendar.get_supported_components = MagicMock(return_value=["VEVENT"]) + calendar.search = MagicMock( + return_value=[ + Event( + None, "0.ics", vevent_with_recurrence_id, calendar, "original-event-uid" + ) + ] + ) + + with patch( + "homeassistant.components.caldav.calendar.caldav.DAVClient" + ) as mock_client: + mock_client.return_value.principal.return_value.calendars.return_value = [ + calendar + ] + assert await async_setup_component( + hass, "calendar", {"calendar": CALDAV_CONFIG} + ) + await hass.async_block_till_done() + + client = await hass_client() + response = await client.get( + f"/api/calendars/{TEST_ENTITY}?start=2017-11-27&end=2017-11-28" + ) + assert response.status == HTTPStatus.OK + events = await response.json() + + assert len(events) == 1 + assert events[0]["uid"] == "original-event-uid" + assert events[0]["recurrence_id"] == "2017-11-27 17:00:00+00:00" + assert events[0]["summary"] == "Modified occurrence" + + @pytest.mark.parametrize( ("calendars"), [