Convert EXDATE and RDATE to same type as DTSTART
Fixes #1146 Closes #1199
This commit is contained in:
parent
537737da32
commit
a20791e0c3
@ -24,11 +24,13 @@ Module for address books and calendar entries (see ``Item``).
|
||||
"""
|
||||
|
||||
import binascii
|
||||
import contextlib
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
from hashlib import sha256
|
||||
from itertools import chain
|
||||
from typing import (Any, Callable, List, MutableMapping, Optional, Sequence,
|
||||
Tuple)
|
||||
|
||||
@ -142,6 +144,28 @@ def check_and_sanitize_items(
|
||||
logger.debug("Quirks: Removing zero duration from %s in "
|
||||
"object %r", component_name, component_uid)
|
||||
del component.duration
|
||||
# Workaround for Evolution
|
||||
# EXDATE has value DATE even if DTSTART/DTEND is DATE-TIME.
|
||||
# The RFC is vaguely formulated on the issue.
|
||||
# To resolve the issue convert EXDATE and RDATE to
|
||||
# the same type as DTDSTART
|
||||
if hasattr(component, "dtstart"):
|
||||
ref_date = component.dtstart.value
|
||||
ref_value_param = component.dtstart.params.get("VALUE")
|
||||
for dates in chain(component.contents.get("exdate", []),
|
||||
component.contents.get("rdate", [])):
|
||||
replace_value_param = False
|
||||
for i, date in enumerate(dates.value):
|
||||
if type(date) != type(ref_date):
|
||||
replace_value_param = True
|
||||
dates.value[i] = ref_date.replace(
|
||||
date.year, date.month, date.day)
|
||||
if replace_value_param:
|
||||
if ref_value_param is None:
|
||||
with contextlib.suppress(KeyError):
|
||||
del dates.params["VALUE"]
|
||||
else:
|
||||
dates.params["VALUE"] = ref_value_param
|
||||
# vobject interprets recurrence rules on demand
|
||||
try:
|
||||
component.rruleset
|
||||
@ -176,9 +200,9 @@ def check_and_sanitize_items(
|
||||
else:
|
||||
vobject_item.add("UID").value = object_uid
|
||||
else:
|
||||
for i in vobject_items:
|
||||
for item in vobject_items:
|
||||
raise ValueError("Item type %r not supported in %s collection" %
|
||||
(i.name, repr(tag) if tag else "generic"))
|
||||
(item.name, repr(tag) if tag else "generic"))
|
||||
|
||||
|
||||
def check_and_sanitize_props(props: MutableMapping[Any, Any]
|
||||
|
33
radicale/tests/static/event_mixed_datetime_and_date.ics
Normal file
33
radicale/tests/static/event_mixed_datetime_and_date.ics
Normal file
@ -0,0 +1,33 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:Europe/Paris
|
||||
X-LIC-LOCATION:Europe/Paris
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
TZNAME:CEST
|
||||
DTSTART:19700329T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
TZNAME:CET
|
||||
DTSTART:19701025T030000
|
||||
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
CREATED:20130902T150157Z
|
||||
LAST-MODIFIED:20130902T150158Z
|
||||
DTSTAMP:20130902T150158Z
|
||||
UID:event_mixed_datetime_and_date
|
||||
SUMMARY:Event
|
||||
DTSTART;TZID=Europe/Paris:20130901T180000
|
||||
DTEND;TZID=Europe/Paris:20130901T190000
|
||||
RRULE:FREQ=DAILY;COUNT=3
|
||||
EXDATE;VALUE=DATE:20130902
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
@ -97,6 +97,12 @@ permissions: RrWw""")
|
||||
assert xml.tag == xmlutils.make_clark("D:error")
|
||||
assert xml.find(xmlutils.make_clark("C:no-uid-conflict")) is not None
|
||||
|
||||
def test_add_event_with_mixed_datetime_and_date(self) -> None:
|
||||
"""Test event with DTSTART as DATE-TIME and EXDATE as DATE."""
|
||||
self.mkcalendar("/calendar.ics/")
|
||||
event = get_file_content("event_mixed_datetime_and_date.ics")
|
||||
self.put("/calendar.ics/event.ics", event)
|
||||
|
||||
def test_add_todo(self) -> None:
|
||||
"""Add a todo."""
|
||||
self.mkcalendar("/calendar.ics/")
|
||||
|
Loading…
Reference in New Issue
Block a user