caldav_sync: no longer create past events in Odoo when synchronizing from CalDAV server
This commit is contained in:
parent
c3af7223de
commit
2e15f18285
3 changed files with 33 additions and 7 deletions
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "CalDAV Synchronization",
|
"name": "CalDAV Synchronization",
|
||||||
"version": "18.0.0.6.3",
|
"version": "18.0.0.7.0",
|
||||||
"license": "LGPL-3",
|
"license": "LGPL-3",
|
||||||
"category": "Productivity",
|
"category": "Productivity",
|
||||||
"summary": "Synchronize Odoo Calendar Events with CalDAV Servers",
|
"summary": "Synchronize Odoo Calendar Events with CalDAV Servers",
|
||||||
|
|
|
||||||
|
|
@ -584,11 +584,11 @@ class CalendarEvent(models.Model):
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _sync_event_from_ical(
|
def _sync_event_from_ical(
|
||||||
self, ical_event: icalendar.cal.Event, user: User
|
self, ical_event: icalendar.cal.Event, user: User
|
||||||
) -> CalendarEvent:
|
) -> CalendarEvent:
|
||||||
"""Given an iCalendar event, compare the event with any existing
|
"""Given an iCalendar event, compare the event with any existing
|
||||||
Odoo event that it matches and synchronize the changes. If no event
|
Odoo event that it matches and synchronize the changes. If no event
|
||||||
exists, create one.
|
exists, create one iff the event is in the future.
|
||||||
|
|
||||||
:param ical_event: The iCalendar event to synchronize with Odoo.
|
:param ical_event: The iCalendar event to synchronize with Odoo.
|
||||||
:param user: The res.user record for whom to synchronize the event.
|
:param user: The res.user record for whom to synchronize the event.
|
||||||
|
|
@ -609,12 +609,15 @@ class CalendarEvent(models.Model):
|
||||||
existing_instance = self._get_existing_instance(uid, recurrence_id)
|
existing_instance = self._get_existing_instance(uid, recurrence_id)
|
||||||
outdated = self._get_outdated(component, existing_instance, synced_events)
|
outdated = self._get_outdated(component, existing_instance, synced_events)
|
||||||
owned = (
|
owned = (
|
||||||
existing_instance and existing_instance.partner_id == user.partner_id
|
existing_instance and existing_instance.partner_id == user.partner_id
|
||||||
)
|
)
|
||||||
# Pass for_creation=True only when creating a new event
|
# Pass for_creation=True only when creating a new event
|
||||||
values = self._get_values_from_ical_component(component, user, for_creation=not existing_instance)
|
values = self._get_values_from_ical_component(component, user, for_creation=not existing_instance)
|
||||||
recurrency_vals = self._get_recurrency_values_from_ical_event(component)
|
recurrency_vals = self._get_recurrency_values_from_ical_event(component)
|
||||||
if not existing_instance:
|
if not existing_instance:
|
||||||
|
# If the event is in the past, we just ignore it.
|
||||||
|
if values.get("stop") < datetime.now(tz=None):
|
||||||
|
continue
|
||||||
# If we're creating an instance and it doesn't follow the recurrence,
|
# If we're creating an instance and it doesn't follow the recurrence,
|
||||||
# just scrap the recurrency vals, they're not useful
|
# just scrap the recurrency vals, they're not useful
|
||||||
if not recurrency_vals.get("follow_recurrence"):
|
if not recurrency_vals.get("follow_recurrence"):
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ def _get_ics_path(filename):
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None):
|
def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None, futurize=True):
|
||||||
with (
|
with (
|
||||||
patch("caldav.DAVClient") as MockDAVClient,
|
patch("caldav.DAVClient") as MockDAVClient,
|
||||||
patch("caldav.Calendar") as MockCalendar,
|
patch("caldav.Calendar") as MockCalendar,
|
||||||
|
|
@ -46,8 +46,8 @@ def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None):
|
||||||
# Get or create the mock calendar for this user
|
# Get or create the mock calendar for this user
|
||||||
mock_calendar = calendar_side_effect(user.caldav_calendar_url)
|
mock_calendar = calendar_side_effect(user.caldav_calendar_url)
|
||||||
|
|
||||||
def event_by_uid_side_effect(self, uid):
|
def event_by_uid_side_effect(uid):
|
||||||
for event in self.events():
|
for event in mock_calendar.events():
|
||||||
if str(event.icalendar_component.get("uid")) == uid:
|
if str(event.icalendar_component.get("uid")) == uid:
|
||||||
return event
|
return event
|
||||||
return DEFAULT
|
return DEFAULT
|
||||||
|
|
@ -66,6 +66,18 @@ def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None):
|
||||||
if subcomponent.name == "VEVENT":
|
if subcomponent.name == "VEVENT":
|
||||||
subcomponent["last-modified"] = icalendar.vDate(last_modified)
|
subcomponent["last-modified"] = icalendar.vDate(last_modified)
|
||||||
subcomponent["dtstamp"] = icalendar.vDate(last_modified)
|
subcomponent["dtstamp"] = icalendar.vDate(last_modified)
|
||||||
|
if futurize:
|
||||||
|
for event in ical_events:
|
||||||
|
for subcomponent in event.subcomponents:
|
||||||
|
if subcomponent.name == "VEVENT":
|
||||||
|
start = subcomponent.get("dtstart") and subcomponent.decoded("dtstart")
|
||||||
|
end = subcomponent.get("dtend") and subcomponent.decoded("dtend")
|
||||||
|
if isinstance(start, datetime) and isinstance(end, datetime):
|
||||||
|
duration = end - start
|
||||||
|
else:
|
||||||
|
duration = timedelta(hours=1)
|
||||||
|
subcomponent["dtstart"] = icalendar.vDDDTypes(datetime.now())
|
||||||
|
subcomponent["dtend"] = icalendar.vDDDTypes(datetime.now() + duration)
|
||||||
|
|
||||||
base_events = [event for event in ical_events if not event.get("recurrence-id")]
|
base_events = [event for event in ical_events if not event.get("recurrence-id")]
|
||||||
for base_event in base_events:
|
for base_event in base_events:
|
||||||
|
|
@ -123,6 +135,16 @@ class TestCalendarEvent(TransactionCase, CaldavTestCommon):
|
||||||
new_events = events_after_sync - current_events
|
new_events = events_after_sync - current_events
|
||||||
self.assertEqual(len(new_events), 1)
|
self.assertEqual(len(new_events), 1)
|
||||||
|
|
||||||
|
def test_basic_past_event_from_server_no_create(self):
|
||||||
|
user = self.user_1
|
||||||
|
ics_path = _get_ics_path("basic.ics")
|
||||||
|
with _patch_caldav_with_events_from_ics(ics_path, user, futurize=False):
|
||||||
|
current_events = self.env["calendar.event"].search([])
|
||||||
|
self.env["calendar.event"].poll_caldav_server()
|
||||||
|
events_after_sync = self.env["calendar.event"].search([])
|
||||||
|
new_events = events_after_sync - current_events
|
||||||
|
self.assertEqual(len(new_events), 0)
|
||||||
|
|
||||||
def test_basic_event_from_server_update(self):
|
def test_basic_event_from_server_update(self):
|
||||||
user = self.user_1
|
user = self.user_1
|
||||||
ics_path = _get_ics_path("basic.ics")
|
ics_path = _get_ics_path("basic.ics")
|
||||||
|
|
@ -239,6 +261,7 @@ class TestCalendarEvent(TransactionCase, CaldavTestCommon):
|
||||||
self.assertIn(user2.partner_id, event.partner_ids)
|
self.assertIn(user2.partner_id, event.partner_ids)
|
||||||
self.assertIn(user3.partner_id, event.partner_ids)
|
self.assertIn(user3.partner_id, event.partner_ids)
|
||||||
|
|
||||||
|
|
||||||
def test_multiple_user_attendees_event_from_server_update(self):
|
def test_multiple_user_attendees_event_from_server_update(self):
|
||||||
"""Test event has (as in above test):
|
"""Test event has (as in above test):
|
||||||
Organizer: user1 (test1@example.com)
|
Organizer: user1 (test1@example.com)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue