Adding Events to Secondary Google Calendars

Posted on timeSeptember 1st, 2008 by useryesteray in catGCalendar, GData    flagNo Comments


The most frequently asked question posed in the Google Calendar Date API Group is, “How do I add events to a secondary calendar?”

In this series of posts, I am going to attempt to provide an answer for using every language that has a client library. I discuss the “official” client libraries for Python, Php, .NET, Java and Javascript as well as the slightly less official Objective-C library and some of the attempts to create Ruby library for interacting with Google Calendar and GData. If there are other client libraries, just let me know in the comments and I’ll add instructions here, or link to them elsewhere as I have time, interest and understanding.

I start with describing how to POST XML to a calendar url. This is “The Protocol”. You should read this information about the protocol, even if you plan to use a client library. Each client library is using this protocol under the covers, so understanding what is happening will help you better use your client library. In addition, I’ll only explain some terms in this section, so you’ll need to read it to understand what I am talking about.

All information in these posts comes from the Google Developer’s Guides, the Client Library Documentation, the source code for the client library and my own exploration and testing. I’ll provide links to these resources in the text as appropriate. For simplicity’s sake, I only cover creating single-occurrence events for users that have properly authenticated using client login. These cases should be sufficient for illustrating how to add to secondary calendars, but 1) I’m not aware of any differences in creating single-occurrence versus quickadd or recurrent events on secondary calendars in any of the client libraries and 2) I haven’t used AuthSub.

I have personally tested all of the code that I present here, unless otherwise noted. That means that I was able to create an event on a calendar using that code. In all cases, I am adding events to my Secondary Calendar which is public, so have a look. I’ll be trying to add an event that occurs at the time when the relevant article is posted.

Here is a table of contents of the language-specific treatments. I’ll update the links as I complete the sections.

Python
Php
.NET
Java
Javascript
Objective C
Ruby

Read the rest of this entry »

tag



Link Elements in GCalendar Calendar Feeds

Posted on timeMay 15th, 2008 by useryesteray in catCalendar, GCalendar, GData    flagNo Comments


Here for reference is a complete listing of the rel and type attributes I have observed for link elements in Google Calendar feeds. These are a superset of the attributes contained in link elements found in event feeds. Google Calendar feeds do not use all available combinations of permitted Atom link elements. A complete list of Atom link relations is here. Atom requires that each element have a maximum of one link of each relation and type. Types are specified here for Atom elements. None of the observed relations from outside the Atom namespace have types.

link rel='alternate' type='application/atom+xml'
link rel='alternate' type='text/calendar'
link rel='alternate' type='text/html'
link rel='edit' type='application/atom+xml'
link rel='http://schemas.google.com/acl/2007#accessControlList'
link rel='http://schemas.google.com/g/2005#batch'
link rel='http://schemas.google.com/acl/2007#controlledObject'
link rel='http://schemas.google.com/g/2005#feed'
link rel='http://schemas.google.com/g/2005#post'
link rel='next' type='application/atom+xml'
link rel='previous' type='application/atom+xml'
link rel='self' type='application/atom+xml'

Notes

Alternate links point to an alternate representation of the same resource. There are three types represented in Google Calendar feeds; the type specifies that nature of the alternate representation. The application/atom+xml type alternate links are all contained inside <entry> elements and point to the individual entry. The text/html type links are to html representations of the calendar or event. The text/calendar are links to ics format calendar files.

The edit links are used to update or delete calendars or events. The post links are used to create calendars or events. The edit links are defined in the Atom Publishing Protocol. Post links are Google’s own invention.

Batch links identify the uri for posting batch request. I have no experience with batch requests, but according to the documentation insert, update, delete, or query operations are permitted.

Feed links in all observed cases are exactly the same as the id of the feed. The self links are related to the feed links and id, but also contain the (possibly implicit) url parameters that were used to retrieve the feed.

AccessControlList links identify the location of the access control list (acl) for the feed. ControlledObject links identify the feed that the acl pertains to.

Next and previous specify Atom Publishing Protocol partial collections. Next and previous are paged feeds.

tag



Persistence of gsessionids

Posted on timeMay 8th, 2008 by useryesteray in catCalendar, GCalendar, GData    flagNo Comments


I’ve read this paragraph many times, but somehow the full meaning just became apparent to me.

Just like in the previous example, Calendar may return an HTTP 302 redirect; if so, then the redirect URL has a new parameter, gsessionid, appended to it. If you received the redirect, then send the same POST request again, with the same Authorization header and the same content, but with the gsessionid parameter appended. The response may also include a S cookie, which you should store and send this cookie with future requests as appropriate. Please see the knowledge base for more information on handling sessions with the Calendar data API. Please note: if a session ID indicated in a cookie header conflicts
with the session ID passed as a gsessionid URL parameter, you will get caught in a redirect loop.

The introductory clause obscures important information. Having read the previous example, I thought that there wasn’t much to be gained by reading this paragraph in detail. Just do the same thing as before, “So after you’ve sent the GET request, you have to read the HTTP headers of the response to find the URL with the session ID appended; then you need to send another GET request with that new URL.”

Really, I didn’t think too much. The gsessionid is a persistent session id. You can send it with any future request and if you do, and the session id matches the auth token your request will be accepted without redirect. Moreover you can grab the S cookie and stick it in your headers and not need to worry about it.This is documented here.

Here’s an example in action:

# get_feed is from a project I'm working on
irb:01:0> require 'get_feed'                         
=> true
# it provides an authorization method that also sets @headers and creates @http object
irb:02:0> get_auth('me@gmail.com','top_secret')      
=> {"Authorization"=>"GoogleLogin auth=DQAAAIQAAABECsmTToeu0o97DoPQ8v9lXDkqFYQY4tOC4QmkItA9jb1J2GfEql69SifsFF7TJJ6_lbAST3iuc-aZQUIvY3qDfPj4pNpo9_XAsCEphd9jRdqeqengYDnpTOEJJedw9jRV738b4x-EluyDKDPBw0f46fFDto0o8zkgY_bUChKK0T6j8A5PgedYRRJzQJm_oSY", "Content-Type"=>"application/atom+xml", "Service"=>"67central.com--get-feed-0.0.1"}
irb:03:0> @headers                                   
=> {"Authorization"=>"GoogleLogin auth=DQAAAIQAAABECsmTToeu0o97DoPQ8v9lXDkqFYQY4tOC4QmkItA9jb1J2GfEql69SifsFF7TJJ6_lbAST3iuc-aZQUIvY3qDfPj4pNpo9_XAsCEphd9jRdqeqengYDnpTOEJJedw9jRV738b4x-EluyDKDPBw0f46fFDto0o8zkgY_bUChKK0T6j8A5PgedYRRJzQJm_oSY", "Content-Type"=>"application/atom+xml", "Service"=>"67central.com--get-feed-0.0.1"}
# User's default calendar and own calendars feeds
irb:04:0> default =  '/calendar/feeds/default'          
=> "/calendar/feeds/default"
irb:05:0> all = '/calendar/feeds/default/owncalendars/full'
=> "/calendar/feeds/default/owncalendars/full"
# Request for feeds are redirected           
irb:06:0> @http.get(default,@headers)       
=> #<Net::HTTPFound 302 Moved Temporarily readbody=true>
irb:07:0> response = @http.get(all,@headers)       
=> #<Net::HTTPFound 302 Moved Temporarily readbody=true>
# All calendars feed to this location, note the gsessionid
irb:08:0> response['Location']                       
=> "https://www.google.com:443/calendar/feeds/default/owncalendars/full?gsessionid=uVGhyT0F60BtaKPNVsOeig"
# Also returns this cookie       
irb:09:0> response['set-cookie']                     
=> "S=calendar=uVGhyT0F60BtaKPNVsOeig;Expires=Fri, 08-May-2009 20:54:31 GMT"
irb:10:0> s_cookie =  response["set-cookie"].split(';').first                                                  
=> "S=calendar=uVGhyT0F60BtaKPNVsOeig"
irb:11:0> all_redirect = "/calendar/feeds/default/owncalendars/full?gsessionid=uVGhyT0F60BtaKPNVsOeig"        
=> "/calendar/feeds/default/owncalendars/full?gsessionid=uVGhyT0F60BtaKPNVsOeig"
# With the gsessionid, request succeeds    
irb:12:0> response = @http.get(all_redirect,@headers)
=> #<Net::HTTPOK 200 OK readbody=true>
irb:13:0> default_with_redirect = default + "?gsessionid=uVGhyT0F60BtaKPNVsOeig"                                        
=> "/calendar/feeds/default?gsessionid=uVGhyT0F60BtaKPNVsOeig"
# So does this one                         
irb:14:0> response = @http.get(default_with_redirect,@headers)
=> #<Net::HTTPOK 200 OK readbody=true>
# Set the cookie                        
irb:15:0> @headers['Cookie'] = s_cookie                
=> "S=calendar=uVGhyT0F60BtaKPNVsOeig"
# And both request succeed without gsessionid                     
irb:16:0> response = @http.get(all,@headers)         
=> #<Net::HTTPOK 200 OK readbody=true>
irb:17:0> response = @http.get(default,@headers)         
=> #<Net::HTTPOK 200 OK readbody=true>

I hope that is useful to some one. There is a claim in the documentation (I’ve temporarily lost it) that the API libraries will handle these session ids and cookies automatically. Good to know.

tag



Link Elements in GCalendar Event Feeds

Posted on timeApril 27th, 2008 by useryesteray in catCalendar, GCalendar, GData    flagNo Comments


A question from the for the Google Calendar Data API Developer Forum.

Hi all,


for (CalendarEventEntry event : calEventList) { 
    for (Link link : event.getLinks()) { 
        System.out.println(link.getHref()); 
} 

above code fragment prints three types of links, what these are meant for?
What these links signify in the feed.

Regards,
Vijay

This is a question that I had been meaning to address, but I was planning to get to it after I addressed all the different urls that are used in the GCalendar API. Actually this question is easier and more straight-forward to answer, so it makes sense to answer this first. I’ll defer the larger questions of GCalendar event feeds and generic Atom feeds for a later post.

Here’s a complete entry feed (as formated with tidy -xml -indent):

<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:batch='http://schemas.google.com/gdata/batch'
xmlns:gCal='http://schemas.google.com/gCal/2005'
xmlns:gd='http://schemas.google.com/g/2005'>
  <id>  http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk</id>
  <published>2008-04-21T22:36:07.000Z</published>
  <updated>2008-04-21T22:36:07.000Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
  term='http://schemas.google.com/g/2005#event' />
  <title type='text'>Tennis with Beth</title>
  <content type='text'>Meet for a quick lesson.</content>
  <link rel='alternate' type='text/html'
  href='http://www.google.com/calendar/event?eid=ZzBwZHNqbDE4ZW05dGNkYXU2YmFxZ2F0a2sgdGQzczMyZTZrMWliN3BrZ2liaTd2NmprdGdAZw'
  title='alternate' />
  <link rel='self' type='application/atom+xml'
 href='http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk' />
  <link rel='edit' type='application/atom+xml'  href='http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk/63344500567' />
  <author>
    <name>Ray Baxter</name>
    <email>me@gmail.com</email>
  </author>
  <gd:comments>
    <gd:feedLink href='http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk/comments' />
  </gd:comments>
  <gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed' />
  <gd:visibility value='http://schemas.google.com/g/2005#event.default' />
  <gd:transparency value='http://schemas.google.com/g/2005#event.opaque' />
  <gCal:uid value='g0pdsjl18em9tcdau6baqgatkk@google.com' />
  <gCal:sequence value='0' />
  <gd:when startTime='2008-04-17T08:00:00.000-07:00'
  endTime='2008-04-17T10:00:00.000-07:00' />
  <gd:who rel='http://schemas.google.com/g/2005#event.organizer'
  valueString=''
  email='td3s32e6k1ib7pkgibi7v6jktg@group.calendar.google.com' />
  <gd:where valueString='Rolling Lawn Courts' />
</entry>

Coming to Vijay’s question, there are three <link> elements in this feed. They are:

<link rel='alternate' type='text/html' href='http://www.google.com/calendar/event?eid=ZzBwZHNqbDE4ZW05dGNkYXU2YmFxZ2F0a2sgdGQzczMyZTZrMWliN3BrZ2liaTd2NmprdGdAZw' title='alternate' />
<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk' />
<link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk/63344500567' />

The links are named for their relations, i.e. the values of their rel attributes.

The first link is the alternate link, so called because it is an alternative version of the content of this event. In this case the alternate version in html format as you can see by the type='text/html' attribute. Because this calendar is public, you can click on that link and see the event in your browser. Try it.

The second link is a self link. That is the the xml feed for this event, and can repull the event from this feed (in the event that Google’s servers are working, which they don’t appear to be currently.) Notice that the http attribute of the self link is exactly the same URL as the <id>.

<id>
http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk</id>
<link rel='self' type='application/atom+xml'
 href='http://www.google.com/calendar/feeds/td3s32e6k1ib7pkgibi7v6jktg%40group.calendar.google.com/private/full/g0pdsjl18em9tcdau6baqgatkk' />

The self link may not have been the location from you pulled the event. You might have pulled an entire calendar of events (which would have it’s own, distinct, self link) or you might have made a query for events matching some pattern and retrieved a number of events for that feed (which would ought have it’s own self link, but I haven’t verified).

Finally there is the edit link. This is the URL that you use to make changes to the event. Sending a DELETE request to this URL will delete the event. Sending a PUT request will replace event’s data with the data that you send.

For reference, the self and alternate link relations are specified as part of the Atom Syndication Format (RFC4287) and the edit relation is specified as part of the Atom Publication Protocol (RFC5023). A convenient table of all the Atom link relations is here. That table will come in handy as we examine the other link relations in GCalendar feeds.


Any other questions? Leave them in the comments and I’ll get to them as I can.

tagTags: , , , ,



Purple Include

Posted on timeAugust 20th, 2007 by useryesteray in catVisual Elements    flagNo Comments


Brad Neuberg has worked up a new release of the Purple Include tool that came out of the Hyperscope project. Brad’s description is here.

Basically Purple Include is a mechanism for including the content of other web pages (local or remote) in the body of your page. Here are a couple of examples. Here is a paragraph from a post of mine about Jane Jacob’s work:

Here are two bullet points from the forgotten wisdom of Donald Rumsfeld:

There are three elements of Purple Include.

  1. Markup that you add your page. Depending on what you are trying to do, you add a p, blockquote, q, pre, div, or span element with an href attribute.
    The first blockquote above came from this:

    <blockquote href="http://www.warmroom.com/yesterdays/2006/11/12/network-effects-of-the-opposite-kind/#xpath(//p[6])"></blockquote>

    The xpath expression, #xpath(//p[6]), identifies the relevant paragraph on the referenced page that will be included into you page.

  2. A javascript that you add to your page.

    <script src="http://codinginparadise.org/projects/purple-include/purple-include.js"></script>

    As you can see, Brad is hosting this script on his site, for rapid development and improvements.

    On load, this java script pulls the marked up elements from your page and makes a call to a service that Brad is running to fetch the content to be included on your page. The script inserts this content into the inner html of the element.

    The content is of the class .included and .includeok. I have styled .included in the dark gray that you see instead of the normal silver that I am using for blockquotes, so you can see the change in color as the content is inserted.

  3. Brad is running the service that the javascript calls. This service is doing the xpath queries on the content of the referenced page to get the returned content.

This is an interesting design. When I read about it, the first thing that I thought about was caching of the content. In my examples, I referenced my own pages, as Brad referenced his in his examples. I am sure that if you can read these pages, then Brad’s service can read the referenced pages. I’m probably not going to change the pages that I referenced, but I could.

This could be either a good thing, or a bad thing depending on your purposes. The bad is that the exact elements on a page are subject to change. The sixth paragraph of my Jacob’s post could become the seventh or the fifth if I changed blog templates, or fixed a typo in the post. When including content from another site, all bets are off. Also, the remote server could be off line or inaccessible. Brad could add a cache to his service so that any given xpath element of a referenced url from a specific referrer would return the cached result. There would need to be some way to clear the cache, but see below.

On the other hand, this could be just what you want. This is a way to add dynamic content directly to your page, and you don’t need to worry about updating. For many purposes, having a remote server off line isn’t that big a deal and you are likely to be dealing with more fixed markup than I see on my blog pages. A properly scoped xpath query could pull out exactly what you want from most sites.

A couple of other little things that I came across while playing with this.

You can’t include the same exact url (including xpath parameters) twice. The script uses a hash to map from urls to elements. The server returns the content, the url, and an error and looks up the element in the hash by url. Here is the first of Rumsfeld’s pithy sayings from above:

And here it is again:

Only the second appears; the first is just the roller gif. (You can also see that the styling is different.) This is a bug, or at least an unanticipated use case. You can work around by referring to a non-existent query parameter, so urls

href="http://www.warmroom.com/yesterdays/2006/11/08/rumsfelds-rules/?1#xpath(//div[@class='entry']//li[1])"

and

href="http://www.warmroom.com/yesterdays/2006/11/08/rumsfelds-rules/?2#xpath(//div[@class='entry']//li[2])"

Produce

and

respectively.

Finally, the href attribute isn’t valid with any of p, blockquote, q, pre, div, or span in either html 4 or xhtml. This page is invalid.

tag



Marcus Bains Line

Posted on timeJune 5th, 2007 by useryesteray in catCalendar, Visual Elements    flagNo Comments


A useful visual element that can be added to an online calendar is the Marcus Bains Line. Here is a reference and an example.

The line indicates the current time on a daily calendar.

tag



Limitation on Recurring Events in Google Calendar

Posted on timeJune 5th, 2007 by useryesteray in catCalendar, GData    flagNo Comments


Trying to plan a calendar for a group I belong to, I found an old thread from Jeremy with many useful links to the state of calendar solution in early 2005.

One interesting link that I found in the comments was this post from Denka, who points out the Google’s Calendar implementation is hobbled by patents. In particular, the display of an event is limited in both Google’s online calendar, or in the xml feed from that calendar, if single events are requested. (singleevents=true is a query parameter in the GData API that expands recurrent events to single events.)

For instance, I created a calendar with a single event that recurs every day, beginning on June 9th, 2007. Using the web interface to the calendar, the last day that this recurring event appears is June 7th, 2008. There are exactly 365 recurrences of the event (2008 is a leap year). You can see the calendar here, although it will be interesting to see what happens after June 9th passes.

I see the same behavior in the xml feed for the calendar. Note that that feed url has the appended query parameters singleevents=true and max-results=400. Also note that Google has used two different styles for creating parameters from compound phrases.

I manually pulled the results from that feed 6 times to figure out what the restrictions were. Here are the resulting file sizes using wget:

-rw-r--r--   1 ray  wheel   36418 Jun  5 01:06 basic?singleevents=true
-rw-r--r--   1 ray  wheel  419435 Jun  5 01:06 basic?singleevents=true&max-results=300
-rw-r--r--   1 ray  wheel  507095 Jun  5 01:06 basic?singleevents=true&max-results=364
-rw-r--r--   1 ray  wheel  508280 Jun  5 01:06 basic?singleevents=true&max-results=365
-rw-r--r--   1 ray  wheel  508280 Jun  5 01:06 basic?singleevents=true&max-results=366
-rw-r--r--   1 ray  wheel  508280 Jun  5 01:06 basic?singleevents=true&max-results=400

Once you have 365 instances of the recurring event in the feed, you don’t get any more data no matter how many you request.

Interestingly, the ics feed doesn’t have this problem and neither would the xml feed if I weren’t using the singleevents parameter. You get a single event with a start, and no end. The xml feed actually contains the VEVENT recurrence data.

Denka says that Microsoft has sewn up the patents in this area so Google had to treat recurrent events this way.

[Update: 2007-07-02] After June 9th passed, nothing changed. Both the feed and the web have only the same 365 events. There are no events after June 7, 2008. You can see this very clearly if you add the start-min parameter to the query string, as in this link which returns no results. Interestingly the date stamp on the returned file is June 5, the last day that I modified the calendar.


-rw-r--r--   1 ray  wheel  1530 Jun  5 01:41 basic?singleevents=true&start-min=2008-06-08

tag



Search: