浏览代码

Fix ical file generation (#505)

Description of change

Fixes #467

As it stands, Outlook for Mac has a higher standard of compliance to the iCalendar standard, which our EventOccurencePage exports to. This higher standard was causing imported event for our .ics files to fail on calendar sync, and be deleted from the calendar.

To correct this three things have been changed:

    Additional fields have been added to the calendar (prodid and version), which are required for compliance.
    Additional fields have been added to the event (dtstamp and uid) which are required for compliance.
    The datetimes presented for dt_start and dt_end have been converted to UTC. The existing timezoned datetimes were being improperly formatted, which was what was actually breaking the imports.

Tests

An event was manually exported from an existing project to and .ics file, and imported into a freshly installed outlook for mac. This event was successfully added and editable.
Notes

While these changes correct the existing issue, the fact that the package used for handling iCalendar did not enforce compliance, and that its formatting broke with utc timezones make it a liability to use. In the future it should probably be removed for a simple formatted string/dict instead.
Jeremy Childers 2 年之前
父节点
当前提交
84934857a0
共有 2 个文件被更改,包括 17 次插入0 次删除
  1. 11 0
      coderedcms/models/page_models.py
  2. 6 0
      coderedcms/views.py

+ 11 - 0
coderedcms/models/page_models.py

@@ -845,14 +845,25 @@ class CoderedEventPage(CoderedWebPage, BaseEvent):
         ical_event.add('summary', self.title)
         # needs to get full page url, not just slug
         desc_str = _('Details')
+        ical_event.add('dtstamp', timezone.now())
         ical_event.add('description', f'{desc_str}: {self.full_url}')
+        # NOTE: The use of the url for the id is technically breaking the iCal standard,
+        #  which recommends against use of identifiable info:
+        # https://icalendar.org/New-Properties-for-iCalendar-RFC-7986/5-3-uid-property.html
+        # If this breaks in the future,
+        # implementing a uuid field on the object is probably necessary.
+        ical_event.add('uid', self.get_full_url())
         if self.address:
             ical_event.add('location', self.address)
 
         if dt_start:
+            # Convert to utc to remove timezone confusion
+            dt_start = dt_start.astimezone(timezone.utc)
             ical_event.add('dtstart', dt_start)
 
             if dt_end:
+                # Convert to utc to remove timezone confusion
+                dt_end = dt_end.astimezone(timezone.utc)
                 ical_event.add('dtend', dt_end)
 
             # Add a reminder alarm

+ 6 - 0
coderedcms/views.py

@@ -150,6 +150,8 @@ def event_generate_single_ical_for_event(request):
 
     # Generate the ical file.
     ical = Calendar()
+    ical.add('prodid', '-//Wagtail CRX//')
+    ical.add('version', '2.0')
     ical.add_component(event.create_single_ical(dt_start=dt_start, dt_end=dt_end))
     response = HttpResponse(ical.to_ical(), content_type="text/calendar")
     response['Filename'] = "{0}.ics".format(event.slug)
@@ -173,6 +175,8 @@ def event_generate_recurring_ical_for_event(request):
 
     # Generate the ical file.
     ical = Calendar()
+    ical.add('prodid', '-//Wagtail CRX//')
+    ical.add('version', '2.0')
     for e in event.create_recurring_ical():
         ical.add_component(e)
     response = HttpResponse(ical.to_ical(), content_type="text/calendar")
@@ -197,6 +201,8 @@ def event_generate_ical_for_calendar(request):
 
     # Generate the ical file.
     ical = Calendar()
+    ical.add('prodid', '-//Wagtail CRX//')
+    ical.add('version', '2.0')
     for event_page in page.get_index_children():
         for e in event_page.specific.create_recurring_ical():
             ical.add_component(e)