Open dozed opened 2 months ago
Here is a minimal working example test case:
import socket
import tempfile
import threading
import time
from datetime import datetime
import icalendar
import pytest
import radicale
import radicale.server
import requests
from caldav import DAVClient
from caldav.objects import Calendar
@pytest.fixture
def radicale_calendar():
radicale_host = 'localhost'
radicale_port = 52121
url = f'http://{radicale_host}:{radicale_port}/'
username = 'user'
password = 'some-password'
serverdir = tempfile.TemporaryDirectory()
serverdir.__enter__()
configuration = radicale.config.load()
configuration.update(
{
'server': {'hosts': f'127.0.0.1:{radicale_port}'},
'storage': {'filesystem_folder': serverdir.name}
}
)
shutdown_socket, shutdown_socket_out = socket.socketpair()
radicale_thread = threading.Thread(
target=radicale.server.serve,
args=(configuration, shutdown_socket_out),
)
radicale_thread.start()
i = 0
while True:
try:
requests.get(url)
break
except:
time.sleep(0.05)
i += 1
assert i < 100
client = DAVClient(url=url, username=username, password=password)
principal = client.principal()
calendar = principal.make_calendar(
name='Yep', cal_id='123'
)
yield calendar
shutdown_socket.close()
serverdir.__exit__(None, None, None)
recurring_event_with_exception = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
BEGIN:VEVENT
UID:c26921f4-0653-11ef-b756-58ce2a14e2e5
DTSTART;VALUE=DATE:20240411
DTEND;VALUE=DATE:20240412
DTSTAMP:20240429T181103Z
LAST-MODIFIED:20240429T181103Z
RRULE:FREQ=WEEKLY;INTERVAL=2
SEQUENCE:1
SUMMARY:Test 1
X-MOZ-GENERATION:1
END:VEVENT
BEGIN:VEVENT
UID:c26921f4-0653-11ef-b756-58ce2a14e2e5
RECURRENCE-ID;VALUE=DATE:20240425
DTSTART;VALUE=DATE:20240425
DTEND;VALUE=DATE:20240426
CREATED:20240429T181031Z
DTSTAMP:20240429T181103Z
LAST-MODIFIED:20240429T181103Z
SEQUENCE:1
SUMMARY:Test (edited)
X-MOZ-GENERATION:1
END:VEVENT
END:VCALENDAR"""
def test_expanding_caldav_search_with_recurrent_event_having_exception(radicale_calendar: Calendar):
radicale_calendar.save_event(recurring_event_with_exception)
r = radicale_calendar.search(
start=datetime(2024, 3, 31, 0, 0),
end=datetime(2024, 5, 4, 0, 0, 0),
event=True,
expand=True,
)
assert len(r) == 2
assert 'RRULE' not in r[0].data
assert 'RRULE' not in r[1].data
assert isinstance(r[0].icalendar_component['RECURRENCE-ID'], icalendar.vDDDTypes)
# vDDDTypes(2024-04-11, Parameters({'VALUE': 'DATE'}))
# Fails:
assert isinstance(r[1].icalendar_component['RECURRENCE-ID'], icalendar.vDDDTypes)
# [vDDDTypes(2024-04-25, Parameters({'VALUE': 'DATE'})),
# vDDDTypes(2024-04-25, Parameters({'VALUE': 'DATE'}))]
Thanks for your report, you've done a good job debugging and pinpointing the issue as well as writing up test code. Would you care to make it into a pull request? :-)
Sure, I created a draft pull request: https://github.com/python-caldav/caldav/pull/395
There is still an issue with Xandikos on my machine. Do you have an idea maybe what this could be?
I've had different problems with different versions of Xandikos. Do you get an error message?
I created an iCalendar object as follow:
This leads to an iCalendar object with two events, one master and one exception instance:
When searching for the event via
caldav
, two instances are returned. The second instance contains theRECURRENCE-ID
field twice as shown in the following test case:A possible solution would be to add a check for an already existing
RECURRENCE-ID
value here: https://github.com/python-caldav/caldav/blob/f4d5cd2844df99d15a07b72d4f3adf67635ea03b/caldav/objects.py#L2005-L2007Another option would be to just overwrite the value.