property_name = "google calendar event id"
property_type = 'String'
-exchangelib.CalendarItem.register('gcal_link',ex_gcal_link)
+try:
+ exchangelib.CalendarItem.get_field_by_fieldname('gcal_link')
+except ValueError:
+ exchangelib.CalendarItem.register('gcal_link',ex_gcal_link)
+
+#useful if you want to replay an event
+def drop_from_ex_cache(itemid):
+ with open(cachepath,"rb") as f:
+ cache = pickle.load(f)
+ cache.pop(itemid)
+ with open(cachepath,"wb") as f:
+ pickle.dump(cache,f)
def get_ex_event_by_itemid(calendar,itemid):
return calendar.get(item_id=itemid)
len(deleted)))
return added, deleted, changed
+def rrule_from_ex(event,gcal_tz):
+ if event.type != "RecurringMaster":
+ logger.error("Cannot make recurrence from not-recurring event")
+ return None
+ if event.recurrence is None:
+ logger.error("Empty recurrence structure")
+ return None
+ if isinstance(event.recurrence.pattern,
+ exchangelib.recurrence.DailyPattern):
+ rr = "RRULE:FREQ=DAILY;INTERVAL=%d" % event.recurrence.pattern.interval
+ 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)
+ 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 build_gcal_event_from_ex(event,gcal_tz):
gevent={}
gevent["summary"]=event.subject
gevent["end"]={"date": str(event.end.astimezone(gcal_tz).date())}
gevent["start"]={"date": str(event.start.astimezone(gcal_tz).date())}
else:
- gevent["end"]={"dateTime": event.end.isoformat(),
- "timeZone": event.end.tzname()}
- gevent["start"]={"dateTime": event.start.isoformat(),
- "timeZone": event.start.tzname()}
+ gevent["end"]={"dateTime": event.end.astimezone(gcal_tz).isoformat(),
+ "timeZone": str(gcal_tz)}
+ gevent["start"]={"dateTime": event.start.astimezone(gcal_tz).isoformat(),
+ "timeZone": str(gcal_tz)}
if event.text_body is not None and event.text_body.strip() != '':
gevent["description"] = event.text_body
if event.location is not None:
gcal_id="primary"):
for ev_id in added:
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().insert(calendarId=gcal_id,
- body=gevent).execute()
- event.gcal_link = gevent.get("id")
- event.save()
- events[event.item_id] = events[event.item_id]._replace(changekey=event.changekey,gcal_link=event.gcal_link)
- else:
- logger.warning("recurring events not yet supported")
+ 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
+ print(gevent)
+ else:
+ logger.warning("Unable to set recurrence for %s" % event.item_id)
+ continue #don't make the gcal event
+ gevent = gcal_acct.events().insert(calendarId=gcal_id,
+ 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)
def del_ex_to_gcal(ex_acct, gcal_acct, events, deleted, gcal_id="primary"):
for ev_id in deleted: