chiark / gitweb /
check event isn't already cancelled before deleting
[gooswapper] / gooswapper.py
index 1187be17231d84808ad9756410d75f21d3d46c29..9f4cefa271a7ff60e1ef96d04db36b070e419a98 100644 (file)
@@ -74,6 +74,9 @@ def get_ex_event_by_id_and_changekey(acct,itemid,changekey):
     l=list(acct.fetch([(itemid,changekey)]))
     return list(acct.fetch([(itemid,changekey)]))[0]
 
+def get_gcal_event_by_eventid(gcal_acct,eventId,gcal_id="primary"):
+    return gcal_acct.events().get(calendarId=gcal_id,eventId=eventId).execute()
+
 def get_gcal_recur_instance(gcal_acct,gcal_master,start,gcal_id="primary"):
     ans = gcal_acct.events().instances(calendarId=gcal_id,
                                        eventId=gcal_master,
@@ -153,6 +156,15 @@ def ex_event_changes(old,new):
 def rr_daystr_from_int(i):
     return exchangelib.recurrence._weekday_to_str(i).upper()[:2]
 
+#for monthly patterns, we want the week (or -1 for last) combined with each
+#day specified
+def rr_daystr_monthly(p):
+    if p.week_number == 5:
+        wn = "-1"
+    else:
+        wn = str(p.week_number)
+    return ",".join([wn + rr_daystr_from_int(x) for x in p.weekdays])
+
 def rrule_from_ex(event,gcal_tz):
     if event.type != "RecurringMaster":
         logger.error("Cannot make recurrence from not-recurring event")
@@ -169,18 +181,38 @@ def rrule_from_ex(event,gcal_tz):
                           (event.recurrence.pattern.interval,
                            ",".join([rr_daystr_from_int(x) for x in event.recurrence.pattern.weekdays]),
                            rr_daystr_from_int(event.recurrence.pattern.first_day_of_week) )
+    elif isinstance(event.recurrence.pattern,
+                    exchangelib.recurrence.RelativeMonthlyPattern):
+        rr = "RRULE:FREQ=MONTHLY;INTERVAL=%d;BYDAY=%s" % \
+                     (event.recurrence.pattern.interval,
+                      rr_daystr_monthly(event.recurrence.pattern))
+    elif isinstance(event.recurrence.pattern,
+                    exchangelib.recurrence.AbsoluteMonthlyPattern):
+        rr = "RRULE:FREQ=MONTHLY;INTERVAL=%d;BYMONTHDAY=%d" % \
+                          (event.recurrence.pattern.interval,
+                           event.recurrence.pattern.day_of_month)
+    elif isinstance(event.recurrence.pattern,
+                    exchangelib.recurrence.AbsoluteYearlyPattern):
+        rr = "RRULE:FREQ=YEARLY;BYMONTH=%d;BYMONTHDAY=%d" % \
+                          (event.recurrence.pattern.month,
+                           event.recurrence.pattern.day_of_month)
+    elif isinstance(event.recurrence.pattern,
+                    exchangelib.recurrence.RelativeYearlyPattern):
+        rr = "RRULE:FREQ=YEARLY;BYMONTH=%d;BYDAY=%s" % \
+                          (event.recurrence.pattern.month,
+                           rr_daystr_monthly(event.recurrence.pattern))
     else:
         logger.error("Recurrence %s not supported" % event.recurrence)
         return None
     if isinstance(event.recurrence.boundary,
                   exchangelib.recurrence.EndDatePattern):
         rr += ";UNTIL={0:%Y}{0:%m}{0:%d}".format(event.recurrence.boundary.end)
+    elif isinstance(event.recurrence.boundary,
+                    exchangelib.recurrence.NoEndPattern):
+        pass #no end date to set
     else:
         logger.error("Recurrence %s not supported" % event.recurrence)
         return None
-    if event.modified_occurrences is not None or \
-       event.deleted_occurrences is not None:
-        logger.warning("Modified/Deleted recurrences not supported")
     return [rr]
 
 def modify_recurring(ex_acct,gcal_acct,gcal_tz,
@@ -249,18 +281,24 @@ def add_ex_to_gcal(ex_acct,
                                            body=gevent).execute()
         event.gcal_link = gevent.get("id")
         event.save(update_fields=["gcal_link"])
-        events[event.item_id] = events[event.item_id]._replace(changekey=event.changekey,gcal_link=event.gcal_link)
         if event.type=="RecurringMaster" and (event.deleted_occurrences or \
                                               event.modified_occurrences):
             modify_recurring(ex_acct,gcal_acct,gcal_tz,
                              events,event,gcal_id)
+            #changekey is updated by the above
+            event.refresh()
+        events[event.item_id] = events[event.item_id]._replace(changekey=event.changekey,gcal_link=event.gcal_link)
         
 def del_ex_to_gcal(ex_acct, gcal_acct, events, deleted, gcal_id="primary"):
     for ev_id in deleted:
         if events[ev_id].gcal_link is not None:
-            gcal_acct.events().delete(calendarId=gcal_id,
-                                      eventId=events[ev_id].gcal_link,
-                                      sendUpdates="none").execute()
+            gevent = get_gcal_event_by_eventid(gcal_acct,
+                                               events[ev_id].gcal_link,
+                                               gcal_id)
+            if gevent["status"] != "cancelled":
+                gcal_acct.events().delete(calendarId=gcal_id,
+                                          eventId=events[ev_id].gcal_link,
+                                          sendUpdates="none").execute()
 
 def update_ex_to_gcal(ex_acct,
                       gcal_acct,gcal_tz,
@@ -268,14 +306,24 @@ def update_ex_to_gcal(ex_acct,
                       gcal_id="primary"):
     for ev_id in changed:
         event = get_ex_event_by_itemid(ex_acct.calendar,ev_id)
-        if not event.is_recurring:
-            gevent = build_gcal_event_from_ex(event,gcal_tz)
-            gevent = gcal_acct.events().update(calendarId=gcal_id,
+        gevent = build_gcal_event_from_ex(event,gcal_tz)
+        if event.type=="RecurringMaster":
+            rr = rrule_from_ex(event,gcal_tz)
+            if rr is not None:
+                gevent["recurrence"] = rr
+                if event.deleted_occurrences or \
+                   event.modified_occurrences:
+                    modify_recurring(ex_acct,gcal_acct,gcal_tz,
+                                     events,event,gcal_id)
+                    event.refresh() #changekey is updated by the above
+                    events[event.item_id] = events[event.item_id]._replace(changekey=event.changekey,gcal_link=event.gcal_link)
+            else:
+                logger.warning("Unable to set recurrence for %s" % event.item_id)
+                continue #don't make the gcal event
+        gevent = gcal_acct.events().update(calendarId=gcal_id,
                                                eventId=event.gcal_link,
                                                body=gevent,
                                                sendUpdates="none").execute()
-        else:
-            logger.warning("recurring events not yet supported")
 
 def match_ex_to_gcal(ex_acct,gcal_acct,gcal_tz,events,gcal_id="primary"):
     recur = 0