Table of Contents
Online calendars will move from being merely trendy to virtually indispensable as our lives move increasingly to the network. Calendaring (scheduling appointments and coordinating calendars) is something most of us can relate to since we all have appointments that we make and keep.
As we use electronic calendars, there is a good chance that we will have more than one calendar to synchronize—people use different calendars or work with people with other calendars, no matter how much Microsoft, Apple, Google, or Yahoo! might want everyone to use its calendar alone. A lot of this calendaring activity has moved to not only digital form but specifically to a networked digital form. In addition to the old calendars, new generations of online calendars are coming into existence—that’s the focus of this chapter.
Online calendars exist in the context of other digital calendars: desktop calendars such as Microsoft Outlook and Apple iCal and calendars on handheld devices such as the Palm calendar. Much work has been done on synchronizing these calendars. Of course, calendar synchronization has been operant for a while, but these approaches (specialized conduits/SyncML[230][231]
In addition to the proliferation of online calendars, event aggregation sites such as Upcoming.yahoo.com and Eventful.com are starting to create a marketplace of event data. They are focused on public events, whereas online calendars have as their focal point individuals and private events. These worlds intersect, of course, because individual users often track the public events they attend on their individual calendars.
When it comes to public events, the point of focus is different, depending on whether you are an attendee (and consumer of information about the event) or are a publisher or purveyor of event information. As an individual viewer, you want to browse, aggregate, and select events, typically from multiple sources. You might be conducting these tasks in a social context. What are your friends interested in? What do they invite you to, and vice versa? Your friends might know what you care about and direct you to events you’ll find interesting. As a publisher of events, you probably want to disseminate information about the event as widely as possible. There are technical mechanisms for supporting the interchange of data between publishers of event data and consumers of event data, which is one of the subjects of this chapter.
This chapter shows the first steps to take in learning this subject:
It covers what data you can get in and out of calendars without programming using iCalendar and various XML feeds as examples.
It covers how to program individual calendars using Google Calendar and 30boxes.com, how to move data from a source of event data into calendars, and how to write event information to event aggregators such as Upcoming.yahoo.com and Eventful.com.
Google Calendar is fast increasing in popularity among online calendars.[232]
Let’s talk about how to use Google Calendar as a user first and then look at how to program it.
Log in to your Google account here:
Google Calendar has some noteworthy features:
In addition to creating a main calendar, you can create secondary calendars and subscribe to calendars belonging to others. Because you can turn the visibility of any given calendar on and off, you get a composite view of the events of all your visible calendars. (Think of each calendar as a layer.) On the sidebar, you get a list of your own calendars and the other calendars to which you are subscribing.
You can search for public events and look for public calendars.[233]
You can set the visibility of your calendars to one of three options: make it publicly available to everyone; show only the Free/Busy information availability, that is, show only whether a block of time is occupied; or set it to the Do Not Share with Everyone level, in which case the calendar is visible only to those people with whom you explicitly share your calendar.[234]
To delete a calendar, you have to click the Manage Calendars link.
There is Gmail/Google Calendar integration: “Gmail users can send event invitations directly from their Gmail accounts without accessing Google Calendar.”[235]
There is currently no direct offline access to Google Calendar.[236]
To show some use case scenarios for Google Calendar, here I list some of the calendars that I have set up and the reasons why:
A strictly personal calendar for events. I have set this calendar to Do Not Share with Everyone.
A family and friends calendar for my closest friends. I also use the Do Not Share with Everyone setting here but then add the e-mail addresses of individual friends and family members.
A calendar called Raymond Yee’s Public Events to list events that I plan to be at and don’t mind the world knowing about. I use the Share All Information on This Calendar with Everyone setting.
A calendar called Mashup Guide Demo Calendar, a public calendar I’ll use in this chapter to demonstrate how to program Google Calendar.
When I create a new Google calendar, I consider the following factors:
Who I want to share the calendar with (that is, is the calendar for myself, a specific group of people, or for the whole world?)
The broad topic of that calendar
There are calendar addresses that are visible to others if the calendar is public. There are three formats:[237]
HTML
iCalendar (also known colloquially as iCal)[238]
XML (specifically, Atom feed)
To illustrate the different feed formats, I’ll use a publicly available calendar that I created: the Mashup Guide Demo Calendar, whose sharing status I have set to Share All Information on This Calendar with Everyone.
Every Google calendar has an identifier. The user ID for a user’s main calendar is the user’s e-mail address. For other calendars, the user ID is a more complicated e-mail address. For instance, the user ID for the Mashup Guide Demo Calendar is as follows:
9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com
You can get the HTML feed for a calendar here:
http://www.google.com/calendar/embed?src={userID}
For example:
http://www.google.com/calendar/embed?src=9imfjk71chkcs66t1i436je0s0%40group.calendar. google.com
Associated with the iCalendar and XML feeds are two parameters (visibility
and projection
) that I’ll explain in greater detail in a moment. For instance, you can access an iCalendar feed here:
http://www.google.com/calendar/ical/{userID}/{visibility}/{projection}.ics
For example:
http://www.google.com/calendar/ical/9imfjk71chkcs66t1i436je0s0%40group.calendar. google.com/public/full.ics
and for example:
http://www.google.com/calendar/ical/9imfjk71chkcs66t1i436je0s0%40group.calendar. google.com/public/basic.ics
The Atom feeds are found here:
http://www.google.com/calendar/feeds/{userID}/{visibility}/{projection}
For example:
http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar. google.com/public/basic
If your calendar is not public, there are still private addresses that other applications can use to access the calendar. Note that you can reset these URLs too in case you want to reset access.[239]
The Google Calendar API is built upon GData, the RESTful protocol based on the Atom Publishing Protocol (APP) combined with the Google-specific extensions introduced in Chapter 7.[240][241]
Before I cover how to programmatically interact with the Google Calendar, I’ll first cover what you can do by changing documents. It’s useful to take a look at specific instances of iCalendar and the XML feeds.
iCalendar is a dominant standard for the exchange of calendar data. Based on the older vCalendar standard, iCalendar is sometimes referred to as iCal, which might be confused with the name of the Apple calendaring program of the same name. The iCalendar standard is supported in a wide range of products.
The official documentation for iCalendar is RFC 2445:
http://tools.ietf.org/html/rfc2445
Some other allied standards are built around RFC 2445, but they are beyond the scope of this book:
iCalendar Transport-Independent Interoperability Protocol (iTIP) Scheduling Events, BusyTime, To-dos and Journal Entries (RFC 2446) lays out how calendar servers can exchange calendaring events.[242]
iCalendar Message-Based Interoperability Protocol (iMIP) (RFC 2447) covers the exchange of calendaring data by e-mail.[243]
See the Wikipedia article on iCalendar for a list of the wide range of products that support iCalendar.[244][245]
The structure of an iCalendar file is not based on XML like many of the data exchange formats covered in this book. There have been attempts to cast the iCalendar data model into XML (such as xCal[246]
iCalendar has many features, but there are a few basic things to know about it:
iCalendar has a top-level object: VCALENDAR
.
There are subobjects, including VEVENT
, VTODO
, VJOURNAL
, and VFREEBUSY
.
I’ll focus mostly on the VEVENT
object here—though VFREEBUSY
is generated in Google Calendar when one uses the “Share only my free/busy information (hide details)” mode.
This is a simple example of iCalendar data (with one VEVENT
), quoted from RFC 2445:[247]
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//hacksw/handcal//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:19970714T170000Z DTEND:19970715T035959Z SUMMARY:Bastille Day Party END:VEVENT END:VCALENDAR
To see a more complicated instance of an iCalendar document, you can use Google Calendar via this:
curl "http://www.google.com/calendar/ical/9imfjk71chkcs66t1i436je0s0%40group. calendar.google.com/public/basic.ics"
This gets the iCalendar rendition of my public Mashup Guide Demo Calendar, a version of which is as follows:
BEGIN:VCALENDAR PRODID:-//Google Inc//Google Calendar 70.9054//EN VERSION:2.0 CALSCALE:GREGORIAN METHOD:PUBLISH X-WR-CALNAME:Mashup Guide Demo Calendar X-WR-TIMEZONE:America/Los_Angeles X-WR-CALDESC:a Google Calendar to support mashupguide.net BEGIN:VTIMEZONE TZID:America/Los_Angeles X-LIC-LOCATION:America/Los_Angeles BEGIN:DAYLIGHT TZOFFSETFROM:-0800 TZOFFSETTO:-0700 TZNAME:PDT DTSTART:19700308T020000 RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:-0700 TZOFFSETTO:-0800 TZNAME:PST DTSTART:19701101T020000 RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU END:STANDARD END:VTIMEZONE BEGIN:VEVENT DTSTART;TZID=America/Los_Angeles:20070507T130000 DTEND;TZID=America/Los_Angeles:20070507T140000 DTSTAMP:20070510T155641Z ORGANIZER;CN=Mashup Guide Demo Calendar:MAILTO:9imfjk71chkcs66t1i436je0s0@Â group.calendar.google.com UID:vk021kggr20ba2jhc3vjg6p8ek@google.com CLASS:PUBLIC CREATED:20070510T021623Z DESCRIPTION: LAST-MODIFIED:20070510T021623Z LOCATION:110 South Hall\, UC Berkeley SEQUENCE:0 STATUS:CONFIRMED SUMMARY:Mixing and Remixing Information Class Open House TRANSP:OPAQUE END:VEVENT BEGIN:VEVENT DTSTART;TZID=America/Los_Angeles:20070411T123000 DTEND;TZID=America/Los_Angeles:20070411T140000 DTSTAMP:20070510T155641Z ORGANIZER;CN=Mashup Guide Demo Calendar:MAILTO:9imfjk71chkcs66t1i436je0s0@Â group.calendar.google.com UID:d9btebsfd121lhqc4arhj9727s@google.com CLASS:PUBLIC CREATED:20070411T144226Z DESCRIPTION: LAST-MODIFIED:20070411T144226Z LOCATION: SEQUENCE:0 STATUS:CONFIRMED SUMMARY:Day 22 TRANSP:OPAQUE END:VEVENT END:VCALENDAR
This chapter does not cover the ins and outs of the iCalendar format. I recommend the following ways to learn more about iCalendar:
Read the “Guide to Internet Calendaring” (http://www.ietf.org/rfc/rfc3283.txt
).
There are many standards (http://www.calconnect.org/calendaringstandards.shtml
), but keep especially RFC 2445 in mind.
Know that since iCalendar is rich in features, these features are not evenly implemented among calendars, servers, or libraries that claim to work with iCalendar.
The community is wrestling with a lot of subtleties. That’s why you have organizations such as CalConnect making recommendations about handling recurring events and time zones (http://calconnect.org/recommendations.shtml
).
Interoperability among iCalendar implementations remains a challenge,[248]
Have some good programming libraries on hand to parse and create iCalendar (although it’s hard to know for sure the quality of any given iCalendar library).
Note that work is underway to update the standards: http://www.ietf.org/html.?charters/calsify-charter.html
.
In working with iCalendar, I’ve found the iCalendar Validator (http://severinghaus.org/?
projects/icv/
), based on the iCal4j
library (http://ical4j.sourceforge.net/
), to be useful. You can use it to validate the iCalendar feed for the Mashup Guide Demo Calendar:
http://severinghaus.org/projects/icv/?url=http%3A%2F%2Fwww.google.com%2Fcalendar%2Fi cal%2F9imfjk71chkcs66t1i436je0s0%2540group.calendar.google.com%2Fpublic%2Fbasic.ics
Now compare Google Calendar data formatted as an Atom XML feed, which you can get using this:
curl http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group. calendar.google.com/public/basic
This will return a feed that looks something like this:
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/ opensearchrss/1.0/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:gCal="http://schemas.google.com/gCal/2005"> <id>http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar.Âgoogle.com/public/basic</id> <updated>2007-05-10T02:16:23.000Z</updated> <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/> <title type="text">Mashup Guide Demo Calendar</title> <subtitle type="text">a Google Calendar to support mashupguide.net</subtitle> <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40 group.calendar.google.com/public/basic"/> <link rel="self" type="application/atom+xml" href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40 group.calendar.google.com/public/basic?max-results=25"/> <author> <name>Raymond Yee</name> <email>raymond.yee@gmail.com</email> </author> <generator version="1.0" uri="http://www.google.com/calendar">Google Calendar </generator> <openSearch:totalResults>2</openSearch:totalResults> <openSearch:startIndex>1</openSearch:startIndex> <openSearch:itemsPerPage>25</openSearch:itemsPerPage> <gd:where valueString=""/> <gCal:timezone value="America/Los_Angeles"/> <entry> <id>http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.Â?calendar.google.com/public/basic/vk021kggr20ba2jhc3vjg6p8ek</id> <published>2007-05-10T02:16:23.000Z</published> <updated>2007-05-10T02:16:23.000Z</updated> <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/> <title type="text">Mixing and Remixing Information Class Open House</title> <summary type="html">When: Mon May 7, 2007 1pm to 2pm&nbsp; PDT<br> <br>Where: 110 South Hall, UC Berkeley <br>Event Status: confirmed</summary> <content type="text">When: Mon May 7, 2007 1pm to 2pm&nbsp; PDT<br> <br>Where: 110 South Hall, UC Berkeley <br>Event Status: confirmed</content> <link rel="alternate" type="text/html"  href="http://www.google.com/calendar/event?eid=dmswMjFrZ2dyMjBiYTJqaGMzd mpnNnA4ZWsgOWltZmprNzFjaGtjczY2dDFpNDM2amUwczBAZw" title="alternate"/> <link rel="self" type="application/atom+xml"  href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40 group.calendar.google.com/public/basic/vk021kggr20ba2jhc3vjg6p8ek"/> <author> <name>Mashup Guide Demo Calendar</name> </author> <gCal:sendEventNotifications value="false"/> </entry> <entry> <id>http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar. google.com/public/basic/d9btebsfd121lhqc4arhj9727s</id> <published>2007-04-11T14:42:26.000Z</published> <updated>2007-04-11T14:42:26.000Z</updated> <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/g/2005#event"/> <title type="text">Day 22</title> <summary type="html">When: Wed Apr 11, 2007 12:30pm to 2pm&nbsp; PDT<br> <br>Event Status: confirmed</summary> <content type="text">When: Wed Apr 11, 2007 12:30pm to 2pm&nbsp; PDT<br> <br>Event Status: confirmed</content> <link rel="alternate" type="text/html"  href="http://www.google.com/calendar/event?eid=ZDlidGVic2ZkMTIxbGhxYzRhcmh qOTcyN3MgOWltZmprNzFjaGtjczY2dDFpNDM2amUwczBAZw" title="alternate"/> <link rel="self" type="application/atom+xml"  href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40 group.calendar.google.com/public/basic/d9btebsfd121lhqc4arhj9727s"/> <author> <name>Mashup Guide Demo Calendar</name> </author> <gCal:sendEventNotifications value="false"/> </entry> </feed>
Note the following about this data:
In this section, I will lead you through the basics of programming the Google Calendar API. Since I won’t cover all the details of the API, I refer you to “Google Calendar Data API Developer’s Guide: Protocol” documentation as an excellent place to start. You’ll learn how to set up some calendars and access the right URLs for various feeds.[251]
As with most APIs, you can take two basic approaches: you can work directly with the protocol, which in this case is based on the GData protocol that underlies many Google APIs, including that for Blogger (see Chapter 7), or you can use a language-specific API kit. Here I’ll show you both approaches. Although the latter approach is often more practical, I’ll use this explication of the Calendar API as a chance to review GData (and the concepts of REST in general). To work with the specific language-specific libraries, consult the documentation here:
http://code.google.com/apis/gdata/clientlibs.html
Later, I’ll give a quick rundown on how to use the PHP and Python API kits. You can get started with the documentation for the Calendar API here:
http://code.google.com/apis/calendar/developers_guide_protocol.html
The reference for the API is here:
http://code.google.com/apis/calendar/reference.html
The Google Calendar API is based on GData, which in turn is based on APP with Google-specific extensions. APP is a strictly REST protocol; remember, that means resources are represented as Atom feeds, and you use standard HTTP methods (GET
, POST
, PUT
, and DELETE
) to read, update, create, and delete elements. Here I’ll show you some of the key feeds and how to use them. Before diving into doing so, I’ll first show you how to obtain an authentication token, which you need in order to make full use of these feeds (that is, beyond issuing GET
requests for public feeds).
One of the two authentication methods available to you is documented here:
http://code.google.com/apis/gdata/auth.html
I’ll show you how to use the ClientLogin
technique here. To make authorized access to the API, you will need an authentication token, which you can obtain by making an HTTP POST
request (using the application/x-www-form-urlencoded
content type) to here:
https://www.google.com/accounts/ClientLogin
with a body that contains the following parameters:
Email
: Your Google e-mail (for example, raymond.yee@gmail.com
)
Password
: Your Google password
source
: A string of the form companyName-applicationName-versionID to identify your program (for example, mashupguide.net-Chap15-v1
)
service
: The name of the Google service, which in this case is cl
Using the example parameters listed here, you can package the authentication request with the following curl
invocation:
curl -v -X POST -d "Passwd={passwd}&source=mashupguide.net-Chap15-v1&Email=Â raymond.yee%40gmail.com&service=cl" https://www.google.com/accounts/ClientLogin
If this call succeeds, you will get in the body of the response an Auth
token (of the form Auth=[AUTH-TOKEN]
). Retain the Auth
token for your next calls. You will embed the authentication token in your calls by including the following HTTP request header:
Authorization: GoogleLogin auth=[AUTH-TOKEN]
Tip | |
---|---|
In |
On occasion, you will need to handle HTTP 302 redirects from the API. That is, instead of fulfilling a request, the Google Calendar API sends you a response with a redirect URL appended with the new query parameter gessionid
. You then reissue your request to this new URL.
Tip | |
---|---|
For HTTP |
There are three feed types: calendar (for managing calendars), event (for events contained by calendars), and comment (for representing comments attached to events). Each of the feeds isqualified by two parameters: visibility
and projection
. After I describe visibility
and projection
, I’ll list the various feeds and show how you can access them via curl
. For more details about the feeds, consult this page:
There are two parameters for “specifying” the representation of feeds: visibility
and projec
tion
. The visibility
parameter can be one of public
, private
, or private-[magicCookie
]
. Feeds that are public do not require authorization and are always read-only; public feeds are inaccessible if the user has turned off sharing for the calendar. Feeds that are private do require authentication to use and are potentially writable in addition to being readable (that is, read/write). Finally, feeds that have a visibility of private-[magicCookie]
are read-only and enable private information to be read without authorization. (The magicCookie
encapsulates authentication information.)
The projection
values are listed here:
http://code.google.com/apis/calendar/reference.html#Projection
They include the following:
full
(potentially read/write).
free-busy
(always read-only). This feed shows minimal information about events but does include data about the duration of events (in other words, the <gd:when>
element).
basic
(always read-only). The basic projection produces Atom feeds without any extension elements; the <atom:summary>
and <atom:content>
elements contain HTML descriptions with embedded data about the events.
There are three types of calendar feeds—meta-feed, allcalendars, and owncalendars—which I’ll cover in turn.
The private and read-only meta-feed contains an <entry>
element for each calendar to which the user has access. This list includes both calendars that are owned by the user and ones to which the user is subscribed. You can access the feed at the following URL:
http://www.google.com/calendar/feeds/default
by using this:
curl -L -X GET -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]" Â http://www.google.com/calendar/feeds/default
Let’s look at an instance of an <entry>
. Here is my own default calendar:
<entry> <id>http://www.google.com/calendar/feeds/default/raymond.yee%40gmail.com</id> <published>2007-10-20T18:46:01.839Z</published> <updated>2007-10-19T23:18:04.000Z</updated> <title type="text">Raymond Yee</title> <link rel="alternate" type="application/atom+xml" Â href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/Â private/full"/> <link rel="http://schemas.google.com/acl/2007#accessControlList" Â type="application/atom+xml"Â href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â full"/> <link rel="self" type="application/atom+xml" href="http://www.google.com/calendar/feeds/default/raymond.yee%40gmail.com"/> <author> <name>Raymond Yee</name> <email>raymond.yee@gmail.com</email> </author> <gCal:timezone value="America/Los_Angeles"/> <gCal:hidden value="false"/> <gCal:color value="#2952A3"/> <gCal:selected value="true"/> <gCal:accesslevel value="owner"/> </entry>
Note the three link
elements in the entry for the meta-feed:
rel="alternate"
whose href
is as follows:
http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/private/full
If you were to do an authenticated GET
on this feed, you’d see that this is an event feed containing all the events for the default calendar.
Note how the URL of this feed maps to the following form:
http://www.google.com/calendar/feeds/{userID}/{privacy}/{projection}
Here the user ID is raymond.yee%40gmail.com, visibility
is private
, and projection
is full
.
rel="http://schemas.google.com/acl/2007#accessControlList"
. The following feed gives you the access control list for the given calendar.
http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/full
For this calendar, there is a single entry (I’m the only person who has permissions associated with my default calendar):
<entry> <id>http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â full/user%3Araymond.yee%40gmail.com</id> <updated>2007-10-20T23:14:47.000Z</updated> <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/acl/2007#accessRule"/> <title type="text">owner</title> <content type="text"/> <link rel="self" type="application/atom+xml" Â href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â full/user%3Araymond.yee%40gmail.com"/> <link rel="edit" type="application/atom+xml" Â href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â full/user%3Araymond.yee%40gmail.com"/> <author> <name>Raymond Yee</name> <email>raymond.yee@gmail.com</email> </author> <gAcl:scope type="user" value="raymond.yee@gmail.com"/> <gAcl:role value="http://schemas.google.com/gCal/2005#owner"/> </entry>
rel="self"
http://www.google.com/calendar/feeds/default/raymond.yee%40gmail.com
This feed returns one entry for the default calendar—instead of all the calendars to which the user (raymond.yee@gmail.com
) has access.
The allcalendars feed is a private, potentially read/write feed for controlling subscriptions and settings (such as the display color) for calendars. Inserting or deleting entries to the allcalendars feed is tantamount to subscribing or unsubscribing to existing calendars. You can update personalization settings for your calendars: the color, whether it is hidden, and whether it is selected. You can’t create or delete calendars by manipulating the allcalendars feed; for those actions, you need to use the owncalendars feed.
The URL for the allcalendars feed is here:
http://www.google.com/calendar/feeds/default/allcalendars/full
which you can access with this:
curl -L -X GET -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]" Â http://www.google.com/calendar/feeds/default/allcalendars/full
Note | |
---|---|
You might wonder about the difference between meta-feed and allcalendars since both of them list all the calendars to which a user has access. The allcalendars feed with a |
I’ll now walk you through how to manipulate the allcalendars feed to add and delete a subscription to the Phases of the Moon calendar, one of Google’s public calendars, which is available here:
http://www.google.com/calendar/embed?src=ht3jlfaac5lfd6263ulfh4tql8%40group.calendar. google.com
Note the user ID of the calendar:
ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com
To subscribe to the calendar, create a file (called phases_moon_entry.xml
) with the minimal entry element needed to be the body of the post as follows:
<?xml version='1.0' encoding='UTF-8'?> <atom:entry xmlns:atom="http://www.w3.org/2005/Atom"> <atom:id>ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com</atom:id> </atom:entry>
Next, issue an HTTP POST
request:
curl -v -X POST --data-binary "@phases_of_moon_entry.xml" -H "Content-Type: Â application/atom+xml " -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]" Â http://www.google.com/calendar/feeds/default/allcalendars/full
As mentioned earlier, there’s a good chance you’ll get a 302 HTTP response code to this call:
http://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=Â {gessionid}
For example:
http://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=Â GUWxgPh61GQ
If you do get a 302 HTTP response code, reissue the call to the new URL with this:
curl -v -X POST --data-binary "@phases_of_moon_entry.xml" -H "Content-Type: Â application/atom+xml " -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]" Â http://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=Â {gessionid}
If the request to subscribe to the Phases of the Moon calendar is successful, you’ll get a 201 HTTP response code to indicate a created calendar, along with a response body akin tothis:
<entry> <id>http://www.google.com/calendar/feeds/default/allcalendars/full/Â ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com</id> <published>2007-10-20T23:55:52.611Z</published> <updated>2007-10-14T07:19:30.000Z</updated> <title type="text">Phases of the Moon</title> <summary type="text"/> <link rel="alternate" type="application/atom+xml" Â href="http://www.google.com/calendar/feeds/ht3jlfaac5lfd6263ulfh4tql8%40Â group.calendar.google.com/private/full"/> <link rel="self" type="application/atom+xml"Â href="http://www.google.com/calendar/feeds/default/allcalendars/full/Â ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com"/> <link rel="edit" type="application/atom+xml" Â href="http://www.google.com/calendar/feeds/default/allcalendars/full/Â ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com"/> <author> <name>Phases of the Moon</name> </author> <gCal:timezone value="Etc/GMT"/> <gCal:hidden value="false"/> <gCal:color value="#7A367A"/> <gCal:selected value="false"/> <gCal:accesslevel value="read"/> <gd:where valueString=""/> </entry>
You can then unsubscribe to the Phases of the Moon calendar with the following HTTP DELETE
request:
curl -v -X DELETE -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]"  http://www.google.com/calendar/feeds/default/allcalendars/full/ht3jlfaac5lfd6263ulfh 4tql8%40group.calendar.google.com?gsessionid={gsessionid}
The owncalendars feeds hold data about the calendars that a user owns. This feed is conceptually similar to the allcalendars feed, with one important difference. Instead of subscribing and unsubscribing to calendars, actions on the owncalendars feed are equivalent to creating and destroying calendars. The syntax for manipulating the owncalendars feed is similar to that for the allcallendars feed. For instance, to retrieve the feed, do a GET
to this:
http://www.google.com/calendar/feeds/default/owncalendars/full
For example:
curl -v -L -X GET -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]" Â http://www.google.com/calendar/feeds/default/owncalendars/full
To create a new book-writing calendar, create a file entitled book_writing_calendar_entry.xml
:
<?xml version="1.0" encoding="UTF-8"?> <entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' xmlns:gCal='http://schemas.google.com/gCal/2005'> <title type='text'>Book Writing Schedule</title> <summary type='text'>A calendar to track when I write my book.</summary> <gCal:timezone value='America/Los_Angeles'></gCal:timezone> <gCal:hidden value='false'></gCal:hidden> <gCal:color value='#2952A3'></gCal:color> <gd:where rel='' label='' valueString='Berkeley, CA'></gd:where> </entry>
and do the following POST
(after handling the HTTP 302 redirect):
curl -v -X POST --data-binary "@book_writing_calendar_entry.xml" -H "Content-Type: Â application/atom+xml " -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]" Â http://www.google.com/calendar/feeds/default/owncalendars/full?gsessionid=Â {gsession-id}
Furthermore, you can then update an existing calendar by issuing the appropriate PUT
:
http://www.google.com/calendar/feeds/default/owncalendars/full/{userID}
And you can delete an existing calendar by using DELETE
:
http://www.google.com/calendar/feeds/default/owncalendars/full/{userID}
Now that you have studied the three types of calendar feeds, you’ll look at how to use the event feeds. (I won’t cover comment feeds in this book.) Specifically, let’s look at the simple case of retrieving all the events from a given feed for which you have write privileges. To work with a given calendar, you need to know its user ID. In the instance of my own calendars (the Mashup Guide Demo calendar), the user ID is as follows:
9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com
The syntax of the URL to the feed of the events is as follows:
http://www.google.com/calendar/feeds/{userID}/{privacy}/{projection}
Specifically, you can use a privacy
value of public
and a projection
value of full
since the calendar is a public one to arrive here:
http://www.google.com/calendar/feeds/{userID}/public/full
For example:
http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar. google.com/public/full
which you can confirm is a URL to a feed of all the events on the calendar. To add an event, you need to send an HTTP POST
request (with the proper authentication) here:
http://www.google.com/calendar/feeds/{userID}/private/full
For example:
http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar. google.com/private/full
That is, you create a file by the name of project_showcase_event.xml
with the following content:
<?xml version='1.0' encoding='UTF-8'?> <entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'> <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category> <title type='text'>Project Showcase</title> <content type='text'>A chance for the class to show off their projects</content> <gd:where valueString='110 South Hall'></gd:where> <gd:when startTime="2008-05-12T13:00:00.000-07:00" endTime="2008-05-12T14:00:00.000-07:00"/> </entry>
and issue the following request:
curl -v -X POST --data-binary "@project_showcase_event.xml" -H "Content-Type: Â application/atom+xml " -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]" Â http://www.google.com/calendar/feeds/{userID}/private/full?gsessionid={gsessionid}
where the gsessionid
is the one given in the 302 redirect to create an event on the Mashup Guide Demo calendar.
With an analogous procedure to how you subscribe or unsubscribe to calendars in the allcalendars feed or create calendars through the owncalendars feed, you can create and delete events through the events feed.
Working directly with the GData interface to Google Calendar gives you a lot of flexibility at the cost of tedium. Now we’ll turn to studying how to use two of the API wrappers for Google Calendar. In the next section, I’ll show you how to use the Python API kit. Here, we’ll study the PHP wrapper.
The PHP API kit is documented here:
http://code.google.com/apis/calendar/developers_guide_php.html
The PHP library for accessing Google Calendar is part of the Zend Google Data Client Library, which, in turn, is available as part of the Zend Framework or as a separate download. Note that the library is developed by Zend and works with PHP 5.1.4 or newer. You can download the Zend Framework from this location:
You can read about how to use the Zend Framework to access Google Calendar here:
http://framework.zend.com/manual/en/zend.gdata.calendar.html
You install the Zend framework by copying the files to a directory of your choice. I set up the Zend Framework in this location:
http://examples.mashupguide.net/lib/ZendFramework/
I’ll now illustrate the basics of using this library through two code snippets. Both use the ClientLogin
form of authorization. The first example retrieves a list of a user’s calendars:
<?php require_once 'Zend/Loader.php'; Zend_Loader::loadClass('Zend_Gdata'); Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); Zend_Loader::loadClass('Zend_Gdata_Calendar'); function getGDataClient($user, $pass) { $service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME; $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service); return $client; } function printCalendarList($client) { $gdataCal = new Zend_Gdata_Calendar($client); $calFeed = $gdataCal->getCalendarListFeed(); echo $calFeed->title->text . "\n"; echo "\n"; foreach ($calFeed as $calendar) { echo $calendar->title->text, "\n"; } } $USER = "[USER]"; $PASSWORD = "[PASSWORD]"; $client = getGDataClient($USER, $PASSWORD); printCalendarList($client); ?>
The second code sample retrieves a list of events for a given calendar and prints basic elements for a given event: its ID, title, content, and details about the “where” and “when” of the event:
<?php require_once 'Zend/Loader.php'; Zend_Loader::loadClass('Zend_Gdata'); Zend_Loader::loadClass('Zend_Gdata_ClientLogin'); Zend_Loader::loadClass('Zend_Gdata_Calendar'); function getGDataClient($user, $pass) { $service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME; $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service); return $client; } function printEventsForCalendar($client, $userID) { $gdataCal = new Zend_Gdata_Calendar($client); $query = $gdataCal->newEventQuery(); $query->setUser($userID); $query->setVisibility('private'); $query->setProjection('full'); $eventFeed = $gdataCal->getCalendarEventFeed($query); echo $eventFeed->title->text . "\n"; echo "\n"; foreach ($eventFeed as $event) { echo $event->title->text, "\t", $event->id->text, "\n" ; echo $event->content->text, "\n"; foreach ($event->where as $where) { echo $where, "\n"; } foreach ($event->when as $when) { echo "Starts: " . $when->startTime . "\n"; echo "Ends: " . $when->endTime . "\n"; } # check for recurring events if ($recurrence = $event->getRecurrence()) { echo "recurrence: ", $recurrence, "\n"; } print "\n"; } } $USER = "[USER]"; $PASSWORD = "[PASSWORD]"; # userID for the Mashup Guide Demo calendar $userID = "9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com"; $client = getGDataClient($USER, $PASSWORD); printEventsForCalendar($client, $userID); ?>
Later in the chapter, you will see how to use the PHP Google Calendar library to create events.
You can find the documentation on the Python API kit here:
http://code.google.com/apis/calendar/developers_guide_python.html
To install the library, you can download it from here:
http://code.google.com/p/gdata-python-client/downloads/list
Or you can access the access the Subversion repository for the project here:
http://gdata-python-client.googlecode.com/svn/trunk/
Note | |
---|---|
The following code depends on the |
Here’s some Python code to demonstrate how to list all of your calendars and to list the events on a specific calendar:
""" Chapter 15: simple facade for Python Google Calendar library """ __author__ = 'raymond.yee@gmail.com (Raymond Yee)' EMAIL = '[USER]' PASSWORD = '[PASSWORD]' try: from xml.etree import ElementTree except ImportError: from elementtree import ElementTree import gdata.calendar.service import gdata.calendar import atom class MyGCal: def __init__(self): self.client = gdata.calendar.service.CalendarService() self.client.email = EMAIL self.client.password = PASSWORD self.client.source = 'GCalendarUtil-raymondyee.net-v1.0' self.client.ProgrammaticLogin() def listAllCalendars(self): feed = self.client.GetAllCalendarsFeed() print 'Printing allcalendars: %s' % feed.title.text for calendar in feed.entry: print calendar.title.text def listOwnCalendars(self): feed = self.client.GetOwnCalendarsFeed() print 'Printing owncalendars: %s' % feed.title.text for calendar in feed.entry: print calendar.title.text def listEventsOnCalendar(self,userID='default'): """ list all events on the calendar with userID """ query = gdata.calendar.service.CalendarEventQuery(userID, 'private', 'full') feed = self.client.CalendarQuery(query) for event in feed.entry: print event.title.text, event.id.text, event.content.text for where in event.where: print where.value_string for when in event.when: print when.start_time, when.end_time if event.recurrence: print "recurrence:", event.recurrence.text if __name__ == '__main__': gc = MyGCal() gc.listAllCalendars() # userID for Mashup Guide Demo calendar userID = '9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com' gc.listEventsOnCalendar(userID)
[230] SyncML is now known as Open Mobile Alliance Data Synchronization and Device Management.
[237] http://www.google.com/support/calendar/bin/answer.py?answer=34578&hl=en and http://www.google.com/support/calendar/bin/answer.py?answer=37104&ctx=sibling