caldav_sync: still working on recurrence

This commit is contained in:
Marc Durepos 2024-11-07 08:08:35 -05:00
parent 0e07d42825
commit 421d609abd
2 changed files with 23 additions and 50 deletions

View file

@ -64,7 +64,9 @@ def _extract_vcal_email(vcal_address):
class CalendarEvent(models.Model):
_inherit = "calendar.event"
caldav_uid = fields.Char(string="CalDAV UID", readonly=True)
caldav_uid = fields.Char(
string="CalDAV UID", compute="_compute_caldav_uid", store=True
)
# Recurrence ID in iCalendar is the date or datetime the event would have
# been at if it followed the sequence. It is set by calendar.recurrence
# when applying a recurrence.
@ -84,6 +86,14 @@ class CalendarEvent(models.Model):
#### Field Computation Methods ####
###################################
@api.depends("recurrence_id")
def _compute_caldav_uid(self):
for event in self:
if event.recurrence_id:
event.caldav_uid = event.recurrence_id.caldav_uid
else:
event.caldav_uid = uuid.uuid4()
@api.depends("recurrence_id.dtstart")
def _compute_caldav_recurrence_id(self):
for event in self:
@ -173,9 +183,6 @@ class CalendarEvent(models.Model):
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("caldav_uid"):
vals["caldav_uid"] = str(uuid.uuid4())
events = super(
CalendarEvent, self.with_context({"caldav_no_sync": True})
).create(vals_list)
@ -400,47 +407,6 @@ class CalendarEvent(models.Model):
}
return mapping.get(state, "NEEDS-ACTION")
def _post_recurrence_detach(self):
"""After events are detached from a recurrence, we need to split them up on the
CalDAV server. The caldav_uid that unites events of a series needs to be
separated, making a new uid for each base event (and its recurrences)."""
# Start by deleting the old calendar events since we will need to remake them
_logger.info(
f"Events {self} with CalDAV UIDs "
f"{self.mapped('caldav_uid')} are being "
f"detached."
)
for event in self:
for user in event.caldav_user_ids:
calendar = user._get_caldav_client().calendar(
url=user.caldav_calendar_url
)
try:
caldav_event = event._find_in_caldav_calendar(
calendar, force_recurrence_id=True
)
if caldav_event:
caldav_event.delete()
except caldav.error.NotFoundError:
pass
base_events = self.filtered("is_base_event")
# Assign a new UID for each base event and its recurrences
for event in base_events:
recurrence_events = (
event.recurrence_id and event.recurrence_id.calendar_event_ids | event
)
new_uid = str(uuid.uuid4())
recurrence_events.write({"caldav_uid": new_uid})
def _break_recurrence(self, future=True):
_logger.info(
f"Recurrence breaking for events {self} with CalDAV "
f"UIDs {self.mapped('caldav_uid')}."
)
super()._break_recurrence(future)
self._post_recurrence_detach()
def _find_in_caldav_calendar(
self, calendar: caldav.Calendar, force_recurrence_id: bool = False
) -> Optional[caldav.Event]:

View file

@ -1,11 +1,18 @@
from odoo import models, fields, api
from pytz import timezone, utc
import uuid
import logging
_logger = logging.getLogger(__name__)
class RecurrenceRule(models.Model):
_inherit = "calendar.recurrence"
def _detach_events(self, events):
events = super()._detach_events(events)
events.with_context(dont_notify=True)._post_recurrence_detach()
return events
@api.model
def _default_uid(self):
return uuid.uuid4()
caldav_uid = fields.Char(
default=_default_uid,
readonly=True,
)