Merge pull request #1981 from metallerok/overridden_recurrence_validation
(#1966) overridden recurrence validation
This commit is contained in:
@@ -641,6 +641,23 @@ def _split_overridden_vevents(
|
|||||||
vevent_recurrence = vevent
|
vevent_recurrence = vevent
|
||||||
|
|
||||||
if vevent_recurrence:
|
if vevent_recurrence:
|
||||||
|
# RFC 5545 3.8.4.4: RECURRENCE-ID MUST have the same value type as DTSTART
|
||||||
|
# in the recurring component.
|
||||||
|
base_dtstart = vevent_recurrence.dtstart.value
|
||||||
|
expected_type = datetime.date
|
||||||
|
if isinstance(base_dtstart, datetime.datetime):
|
||||||
|
expected_type = datetime.datetime
|
||||||
|
|
||||||
|
for ov in vevents_overridden:
|
||||||
|
rid = ov.recurrence_id.value
|
||||||
|
if not isinstance(rid, expected_type):
|
||||||
|
raise ValueError(
|
||||||
|
f"component with UID {vevent_recurrence.uid} has "
|
||||||
|
f"incompatible RECURRENCE-ID value type: base DTSTART is "
|
||||||
|
f"{type(base_dtstart).__name__}, but override RECURRENCE-ID is "
|
||||||
|
f"{type(rid).__name__} ({ov.recurrence_id.value!r})"
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
vevent_recurrence, sorted(
|
vevent_recurrence, sorted(
|
||||||
vevents_overridden,
|
vevents_overridden,
|
||||||
|
|||||||
20
radicale/tests/static/event_mixed_recurrence_id_dt_type.ics
Normal file
20
radicale/tests/static/event_mixed_recurrence_id_dt_type.ics
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
BEGIN:VCALENDAR
|
||||||
|
VERSION:2.0
|
||||||
|
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART:20060102T120000Z
|
||||||
|
DURATION:PT1H
|
||||||
|
RRULE:FREQ=DAILY;COUNT=3
|
||||||
|
SUMMARY:Recurring event
|
||||||
|
UID:event_mixed_recurrence_id_dt_type
|
||||||
|
END:VEVENT
|
||||||
|
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART:20060103T140000Z
|
||||||
|
DURATION:PT1H
|
||||||
|
RECURRENCE-ID;VALUE=DATE:20060103
|
||||||
|
SUMMARY:Override with wrong type
|
||||||
|
UID:event_mixed_recurrence_id_dt_type
|
||||||
|
END:VEVENT
|
||||||
|
|
||||||
|
END:VCALENDAR
|
||||||
@@ -698,3 +698,43 @@ permissions: RrWw""")
|
|||||||
status, responses = self.report("/test", request)
|
status, responses = self.report("/test", request)
|
||||||
assert status == 207
|
assert status == 207
|
||||||
assert len(responses) == 0
|
assert len(responses) == 0
|
||||||
|
|
||||||
|
def test_report_with_incompatible_recurrence_id_dt_types(self, caplog) -> None:
|
||||||
|
"""Test report with incompatible RECURRENCE-ID value types (RFC 5545 3.8.4.4)"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
caplog.set_level(logging.WARNING)
|
||||||
|
|
||||||
|
event_id = "event_mixed_recurrence_id_dt_type"
|
||||||
|
start = "20060103T000000Z"
|
||||||
|
end = "20060105T000000Z"
|
||||||
|
|
||||||
|
self.put("/calendar.ics/", get_file_content(f"{event_id}.ics"))
|
||||||
|
|
||||||
|
request = f"""<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||||
|
<D:prop>
|
||||||
|
<C:calendar-data>
|
||||||
|
<C:expand start="{start}" end="{end}"/>
|
||||||
|
</C:calendar-data>
|
||||||
|
</D:prop>
|
||||||
|
<C:filter>
|
||||||
|
<C:comp-filter name="VCALENDAR">
|
||||||
|
<C:comp-filter name="VEVENT">
|
||||||
|
<C:time-range start="{start}" end="{end}"/>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:comp-filter>
|
||||||
|
</C:filter>
|
||||||
|
</C:calendar-query>
|
||||||
|
"""
|
||||||
|
|
||||||
|
status, _, _ = self.request("REPORT", "/calendar.ics/", request)
|
||||||
|
|
||||||
|
assert status == 400
|
||||||
|
|
||||||
|
logs = caplog.messages
|
||||||
|
error_logs = [log for log in logs if "incompatible RECURRENCE-ID value type" in log]
|
||||||
|
assert len(error_logs) > 0
|
||||||
|
assert event_id in error_logs[0]
|
||||||
|
assert "base DTSTART is datetime" in error_logs[0]
|
||||||
|
assert "override RECURRENCE-ID is date" in error_logs[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user