6
votes

I'm trying to sync a google calendar with my rails application. I've been following the documentation provided by Google: Synchronize Resources Efficiently.

My goal is to only sync events one year into the future and split up recurring events into single events so that I don't have to deal with the complexity of recurrence rules and creating child events for recurring parent events.

During the initial sync I set the time_max to be 1 year in the future and during the initial sync I only get recurring events up to one year into the future.

When I perform an incremental sync I pass the sync token and expect to get recurring events limited to within one year of the initial sync's time_max, but this is not what I'm seeing. I am seeing events well past one year (~10 years).

During the incremental sync I'm unable to set a time_max as I get this expected error from Google.

Caught error syncTokenWithRequestRestrictions: Sync token cannot be used with other request restrictions.

Here's the code I use to sync events from google into my application

def sync_from_google
    next_page_token = nil

    begin
      if sync_token.nil? # full sync
        response = @calendar_service.list_events(google_id,
          time_min: Time.now.utc.strftime("%FT%TZ"),
          time_max: 1.year.from_now.utc.strftime("%FT%TZ"),
          single_events: true)
      else # incremental sync
        response = @calendar_service.list_events(google_id,
          sync_token: sync_token,
          page_token: next_page_token,
          single_events: true)
      end

      response.items.each do |gevent|
        GoogleCalendarEvent.create_event(self.id, gevent, nil)
      end
      next_page_token = response.next_page_token

    rescue Google::Apis::ClientError => error
      if error.status_code == 410
        self.unsync
      end
    end while (response.next_sync_token.nil?)

    update_attributes(synced: true, sync_token: response.next_sync_token)
end

Am I being a dummy and missing something obvious?

Should sync_tokens provided by the initial sync store the time range of desired events?

Is there some other way that I can limit the incremental sync's time range?

1
Did you try removing time_max to see if this will still occur? If not, it may be one of the filters sync token is incompatible to use as stated in the Sample code.Mr.Rebot
SingleEvents=true is allowed on incremental sync (just the timeMin and timeMax are not and you should postfilter uninteresting entries that come with incremental sync)luc

1 Answers

4
votes

I ended up removing the single_events param then manually looping through instances of a recurring event manually with a defined time_min & time_max.

Here's the updated code incase anyone stumbles into this in the future.

def sync_from_google
    next_page_token = nil

    begin
      if sync_token.nil? # full sync
        response = @calendar_service.list_events(google_id,
          time_min: Time.now.utc.strftime("%FT%TZ"),
          time_max: 1.year.from_now.utc.strftime("%FT%TZ"))
      else # incremental sync
        response = @calendar_service.list_events(google_id,
          sync_token: sync_token,
          page_token: next_page_token)
      end

      response.items.each do |gevent|
        if gevent.recurrence
            sync_reccuring_events(gevent)
        else
          GoogleCalendarEvent.create_event(self.id, gevent, nil)
        end
      end
      next_page_token = response.next_page_token

    rescue Google::Apis::ClientError => error
      if error.status_code == 410
        self.unsync
      end
    end while (response.next_sync_token.nil?)

    update_attributes(synced: true, sync_token: response.next_sync_token)
end

and the added method to loop through instances of a recurring event

def sync_reccuring_events(google_event)
    next_page_token = nil

    begin
      response = calendar_service.list_event_instances(google_id,
        google_event.id,
        time_min: Time.now.utc.strftime("%FT%TZ"),
        time_max: 1.year.from_now.utc.strftime("%FT%TZ"),
        page_token: next_page_token)

      response.items.each do |gevent|
          GoogleCalendarEvent.create_event(self.id, gevent, nil)
      end
      next_page_token = response.next_page_token

    end while (next_page_token)
end