def save(self, *args, **kwargs): if self.name is None: self.name = "" self.name = self.name[:150].encode('utf-8').strip() if self.description is None: self.description = "" self.description = self.description[:20000] # Validate the color_index field, correct if necessary if self.color_index is None or self.color_index == '': self.color_index = self.EVENT_COLORS_KEYS[0] try: assert int(self.color_index) in range(len(self.EVENT_COLORS_KEYS)) except (ValueError, AssertionError): self.color_index = self.EVENT_COLORS_KEYS[0] made_aware = False if timezone.is_naive(self.start): made_aware = True self.start = ensure_timezone_awareness(self.start, self.timezone) self.end = ensure_timezone_awareness(self.end, self.timezone) super(GEvent, self).save(*args, **kwargs) if made_aware and settings.VERBOSE_PRINT: print "Made datetime timezone aware for GEvent {} with id {}".format( self.name, self.id)
def save(self, *args, **kwargs): if self.name is None: self.name = "" self.name = self.name[:150] if self.description is None: self.description = "" self.description = self.description[:20000] # Validate the color_index field, correct if necessary if self.color_index is None or self.color_index == '': self.color_index = self.EVENT_COLORS_KEYS[0] try: assert int(self.color_index) in range(len(self.EVENT_COLORS_KEYS)) except (ValueError, AssertionError): self.color_index = self.EVENT_COLORS_KEYS[0] made_aware = False if timezone.is_naive(self.start): made_aware = True self.start = ensure_timezone_awareness(self.start, self.timezone) self.end = ensure_timezone_awareness(self.end, self.timezone) super(GEvent, self).save(*args, **kwargs) if made_aware: print "Made datetime timezone aware for GEvent {} with id {}".format(self.name, self.id)
def save(self, *args, **kwargs): self.start = ensure_timezone_awareness(self.start) self.end = ensure_timezone_awareness(self.end) return super(GRecurrence, self).save(*args, **kwargs)
def sync(self, full_sync=False): """ Syncs this calendar. Assumes that the list of calendars for this profile is correct """ print "Syncing calendar {}".format( self.summary.encode('utf-8').strip()) result = None creds = self.user.googlecredentials service = creds.get_service() default_list_args = { 'calendarId': self.calendar_id, 'singleEvents': True, 'maxResults': 2500, } list_args_with_constraints = { # Only sync up to two months in the future 'timeMax': ensure_timezone_awareness(datetime.now() + timedelta(days=60)).isoformat(), } list_args_with_constraints.update(default_list_args) next_page_token = None if full_sync: # Full sync - initial request without sync token or page token result = service.events().list( **list_args_with_constraints).execute() old_events = GEvent.objects.filter(calendar=self) for event in old_events: event.delete() # Delete the DeletedEvents and get a fresh copy from Google deleted_events = DeletedEvent.objects.filter(calendar=self) for event in deleted_events: event.delete() else: # Incremental sync, initial request needs syncToken try: # Google API doesn't accept constraints for the first request in incremental sync result = service.events().list(syncToken=self.next_sync_token, **default_list_args).execute() except Exception as e: t, v, tb = sys.exc_info() if hasattr(e, 'resp') and e.resp.status == 410: # Sync token is no longer valid, perform full sync print "Sync token is no longer valid, perform full sync for calendar {}".format( self.summary.encode('utf-8').strip()) result = service.events().list( **list_args_with_constraints).execute() else: raise t, v, tb # Run the first iteration, for the first request for item in result['items']: self.api_event_to_gevent(item) # Paginate through the rest, if applicable while True: next_page_token = result.get('nextPageToken') if not next_page_token: # We've reached the last page. Store the sync token. self.next_sync_token = result['nextSyncToken'] self.save() break result = service.events().list( pageToken=next_page_token, **list_args_with_constraints).execute() # Assume at this point it's a correctly formatted event for item in result['items']: self.api_event_to_gevent(item) # Make this calendar consistent with existing DeletedEvents deleted_events = DeletedEvent.objects.filter(calendar=self) for d_event in deleted_events: d_event.apply() print "Successfully synced calendar {}".format( self.summary.encode('utf-8').strip()) # Some additional sanity checks # Check for non-duplicate events with the same recurring_event_id start_times = {} for recurrence in GEvent.objects.filter(calendar=self).exclude( recurrence=''): if recurrence.start in start_times.get( recurrence.recurring_event_id, set()): print "Error: Multiple GEvents found with the same start and recurring_event_id" dupe_ids = [ str(dupe.id) for dupe in GEvent.objects.filter( recurring_event_id=recurrence.recurring_event_id, start=recurrence.start) ] print "IDs are {} at time {}".format(", ".join(dupe_ids), recurrence.start) if not start_times.get(recurrence.recurring_event_id, None): start_times[recurrence.recurring_event_id] = set() start_times[recurrence.recurring_event_id].add(recurrence.start)
def sync(self, full_sync=False): result = None creds = self.user.googlecredentials service = creds.get_service() default_list_args = { 'calendarId': self.calendar_id, 'singleEvents': True, 'maxResults': 2500, } list_args_with_constraints = { # Only sync up to two months in the future 'timeMax': ensure_timezone_awareness(datetime.now() + timedelta(days=60)).isoformat(), } list_args_with_constraints.update(default_list_args) next_page_token = None if full_sync: # Full sync - initial request without sync token or page token result = service.events().list(**list_args_with_constraints).execute() old_events = GEvent.objects.filter(calendar=self) for event in old_events: event.delete() # Delete the DeletedEvents and get a fresh copy from Google deleted_events = DeletedEvent.objects.filter(calendar=self) for event in deleted_events: event.delete() else: # Incremental sync, initial request needs syncToken try: # Google API doesn't accept constraints for the first request in incremental sync result = service.events().list(syncToken=creds.next_sync_token, **default_list_args).execute() except Exception as e: t, v, tb = sys.exc_info() if hasattr(e, 'resp') and e.resp.status == 410: # Sync token is no longer valid, perform full sync result = service.events().list(**list_args_with_constraints).execute() else: raise t, v, tb # Run the first iteration, for the first request for item in result['items']: self.api_event_to_gevent(item) # Paginate through the rest, if applicable while True: next_page_token = result.get('nextPageToken') if not next_page_token: # We've reached the last page. Store the sync token. creds.next_sync_token = result['nextSyncToken'] creds.save() break result = service.events().list(pageToken=next_page_token, **list_args_with_constraints).execute() # Assume at this point it's a correctly formatted event for item in result['items']: self.api_event_to_gevent(item) # Make this calendar consistent with existing DeletedEvents deleted_events = DeletedEvent.objects.filter(calendar=self) for d_event in deleted_events: d_event.apply() print "Successfully synced calendar." # Some additional sanity checks # Check for non-duplicate events with the same recurring_event_id start_times = {} for recurrence in GEvent.objects.filter(calendar=self).exclude(recurrence=''): if recurrence.start in start_times.get(recurrence.recurring_event_id, set()): print "Error: Multiple GEvents found with the same start and recurring_event_id" dupe_ids = [str(dupe.id) for dupe in GEvent.objects.filter(recurring_event_id=recurrence.recurring_event_id, start=recurrence.start)] print "IDs are {} at time {}".format(", ".join(dupe_ids), recurrence.start) if not start_times.get(recurrence.recurring_event_id, None): start_times[recurrence.recurring_event_id] = set() start_times[recurrence.recurring_event_id].add(recurrence.start)