caldav_sync: all seems good. further testing to come before merging into 17.0

This commit is contained in:
Marc Durepos 2024-11-08 12:41:02 -05:00
parent 90d05d75a2
commit 992778e353
2 changed files with 50 additions and 16 deletions

View file

@ -539,7 +539,8 @@ class CalendarEvent(models.Model):
:param user: The res.user record for whom to synchronize events.
"""
_logger.info(f"Polling CalDAV server for user {user.name}")
events = user._get_caldav_events()
calendar = user._get_caldav_client().calendar(url=user.caldav_calendar_url)
events = calendar.events()
synced_events = self.env["calendar.event"]
for caldav_event in events:
ical_event = caldav_event.icalendar_instance
@ -556,7 +557,27 @@ class CalendarEvent(models.Model):
)
orphaned_events = orphaned_events._to_sync()
if orphaned_events:
orphaned_events.with_context(caldav_no_sync=True).with_user(user).unlink()
base_orphans = orphaned_events.filtered(
lambda ev: ev.recurrence_id and ev.is_base_event
)
for base_orphan in base_orphans:
try:
if calendar.event_by_uid(base_orphan.caldav_uid):
# There are some events remaining in this recurrence series,
# so we have synchronized them individually.
pass
except caldav.error.NotFoundError:
# There are no more events with this UID, so we need to clear
# out the whole recurrence chain from the Odoo side.
ctx = {"caldav_no_sync": True}
recurrence = base_orphan.recurrence_id
recurrence.calendar_event_ids.with_context(**ctx).with_user(
user
).unlink()
recurrence.with_context(**ctx).with_user(user).unlink()
(orphaned_events - base_orphans).with_context(
caldav_no_sync=True
).with_user(user).unlink()
@api.model
def _sync_event_from_ical(

View file

@ -1,12 +1,13 @@
from collections.abc import Iterable
from odoo.tests import TransactionCase
from odoo import Command
from unittest.mock import patch, MagicMock, PropertyMock
from unittest.mock import patch, MagicMock, DEFAULT
import icalendar
from pathlib import Path
from .common import CaldavTestCommon
from contextlib import contextmanager
from datetime import datetime, UTC, timedelta
import caldav
WEEKDAY_MAP = {
0: "SUN",
@ -28,7 +29,6 @@ def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None):
with (
patch("caldav.DAVClient") as MockDAVClient,
patch("caldav.Calendar") as MockCalendar,
patch("caldav.Event") as MockEvent,
):
mock_client = MockDAVClient.return_value
mock_calendar = MockCalendar.return_value
@ -43,6 +43,12 @@ def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None):
raise Exception("Calendar does not exist.")
mock_calendar.side_effect = calendar_side_effect
def event_by_uid_side_effect(self, uid):
for event in self.events:
if str(event.icalendar_component.get("uid")) == uid:
return event
ical_events = []
if ics_paths:
if not isinstance(ics_paths, Iterable):
@ -51,18 +57,25 @@ def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None):
with ics_path.open("rb") as file:
ical_content = file.read()
ical_events.append(icalendar.Calendar.from_ical(ical_content))
mock_caldav_events = []
for ical_event in ical_events:
mock_event = MockEvent()
mock_event.icalendar_instance = ical_event
if last_modified:
for component in ical_event.walk():
if component.name == "VEVENT":
component["last-modified"] = last_modified.strftime(
"%Y%m%dT%H%M%SZ"
)
mock_caldav_events.append(mock_event)
mock_calendar.events.return_value = mock_caldav_events
if last_modified:
for event in ical_events:
event["last-modified"] = last_modified
event["dtstamp"] = last_modified
base_events = [event for event in ical_events if not event.get("recurrence-id")]
for base_event in base_events:
child_events = [
event
for event in ical_events
if event.get("recurrence-id")
and event.get("uid") == base_event.get("uid")
]
for child_event in child_events:
base_event.add_component(child_event)
mock_calendar.add_event(base_event)
caldav_events = [caldav.Event(data=event) for event in base_events]
mock_calendar.events.return_value = caldav_events
mock_calendar.event_by_uid.side_effect = event_by_uid_side_effect
user._compute_is_caldav_enabled()
yield