Extending Google Calendar to support cross-organizational scheduling

Friday, April 2, 2010 | 11:14 AM

Labels: , , , ,

Editor's Note: This post was written by Gilad Goraly from ScheduleOnce, a company that provides meeting scheduling solutions for Google Calendar. We invited ScheduleOnce to share their experiences building an application on top of Google Apps utilizing some of our APIs.

ScheduleOnce provides meeting scheduling solutions for organizations using Google Apps. Our solutions extend Google Calendar to support cross-organizational scheduling and include private labeling and robust scheduling features. Since our solution is not a standalone application but an add-on to a calendaring and messaging platform, we were looking to integrate it with a platform that is open and inviting for third party vendors. Google Apps was the natural choice.

Google Calendar does a great job when it comes to scheduling meetings with members inside the organization. The free/busy view allows you to see attendee availability and select a time that is good for all. But what do you do when the meeting involves one or more external attendees? With ScheduleOnce it is possible to see the availability of all attendees, both internal and external, across domains, in one simple free/busy interface. The meeting organizer then selects a time and schedules the meeting. It is that simple. Now let’s see what’s behind the scenes and why we chose to develop it for Google Apps.

For the solution to work effectively it should be completely integrated into the user’s messaging and calendaring environment. This is why we chose to work with Google. Google Apps is an open messaging and calendaring platform with a convenient integration framework. We have the following integration points with Google Apps:


  1. The Google Apps Marketplace installation process adds a link in Google’s universal navigation and enables Single Sign On (SSO).

  2. The Google Gadget framework is used to include a gadget in Google Calendar and in Gmail.

  3. The Google Calendar API is used to seamlessly integrate with the user’s calendar.

Now lets look at each integration point and some of the APIs we used to make ScheduleOnce work seamlessly with Google Apps.

Installation from the Google Apps Marketplace

The new Google Apps Marketplace installation process provides two major benefits:
  1. A quick and easy installation process and a link in Google’s universal navigation

  2. Single Sign On (SSO)

Installation process

The Google Apps administrator follows a simple installation wizard. During this process the following is done by ScheduleoOnce:
  1. The Administrator approves a Two Legged OAuth (2LO) calendar API permission for all domain users. This means that ScheduleOnce can access the calendar API of every user in the domain without requiring the user to re-enter their credentials. This is very convenient for the user.

  2. Every user in the domain automatically gets a link to a Personal ScheduleOnce Dashboard on his Google universal navigation. This is set in the installation manifest:
    <Extension id="oneBarLink" type="link">
    <Name>ScheduleOnce</Name>
    <Url>http://apps.scheduleonce.com/render.aspx?source=${DOMAIN_NAME}&amp;page=dashboard</Url>
    </Extension>
  3. The administrator selects a URL and a logo for the application. We use the SSO and ${DOMAIN_NAME} parameter to verify that the user is part of the domain so one cannot maliciously create ScheduleOnce instances. We also use the ${DOMAIN_NAME} parameter for presenting the domain custom logo:
    https://www.google.com/a/${DOMAIN_NAME}/images/logo.gif?alpha=1

Single Sign On (SSO)

During the installation process our URL is "white listed" at Google so we can authenticate the user by their Open ID. Behind the scenes, ScheduleOnce handles the authentication for the user as described here. In addition, the administrator grants permission to access the user calendar API for all the users in the domain. Since authentication for API access is done using 2-Legged-OAuth (2LO) we can directly connect to the user’s calendar.

On the server side there is a service that handles the 2LO requests
// Create a service for making 2LO requests
GOAuthRequestFactory requestFactory = new GOAuthRequestFactory("cl", "yourCompany-YourAppName-v1");
requestFactory.ConsumerKey = <CONSUMER_KEY>;
requestFactory.ConsumerSecret = <CONSUMER_SECERT>;
CalendarService service = new CalendarService(requestFactory.ApplicationName);
service.RequestFactory = requestFactory;
SSO and 2LO provide the needed security with the convenience of a transparent login. With this combination the ScheduleOnce application looks like any other Google Apps application. When trying to access the ScheduleOnce application before authenticating with Google Apps, the user will get the normal Google Apps login (so no one outside the domain can login). When entering the ScheduleOnce application from one of the Google Apps entry points (Google’s universal navigation or one of the gadgets) then the login is done behind the scenes and it is transparent to the user.

Gadgets in Google Calendar, Gmail and the Start Page

We used an OpenSocial gadget for providing meeting management functionality. Authentication here is a bit trickier since it should be done without the user doing anything actively. To identify the user we used SSO and Open ID, allowing the gadget to be installed on any Google Apps gadget container (such as Google Calendar or Gmail).

Gadget initialization includes UI and OpenSocial data request:
function initGadget(){
//Initializing the gadget tabs
tabs.addTab("Pending", {
contentContainer: document.getElementById("pending_id"),
callback: callback
});
tabs.addTab("Scheduled", {
contentContainer: document.getElementById("scheduled_id"),
callback: callback
});
tabs.displayTabs(false);
refresh();

//Initializing the OpenSocial data request
var idspec = opensocial.newIdSpec({ "userId" : "OWNER"});
var req = opensocial.newDataRequest();
req.add(req.newFetchPersonRequest(opensocial.IdSpec.PersonId.OWNER), "get_owner");
req.send(openSocialResponse);
}
where the POST request looks something like this:
function makePOSTRequest(){
var url = baseURL + "GadgetHandler.aspx";
var postdata = {opensocialid : openSocialID};
var params = {};
postdata = gadgets.io.encodeValues(postdata);
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
params[gadgets.io.RequestParameters.POST_DATA]= postdata;
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;
gadgets.io.makeRequest(url, responseHandler, params);
}
When the gadget runs it loads a hidden iframe to check if the user (by his Open ID) is authenticated on the server. If the user is not authenticated, authentication is done behind the scenes and the user’s Open ID is added to a temporary application object. If the user’s Open ID mapping exists on the application object it means the user is authenticated and can work freely in the ScheduleOnce application.

Integration with Google Calendar

Google Calendar is accessed using the Google Calendar API. Three major functions are used:
  1. Getting the user's busy times: Since availability is dynamic and dependent on the current calendar status we update it every time it is needed. This ensures there will never be any double booking in the user’s calendar.
    // Retrieving the calendar events for a time frame
    EventQuery query = new EventQuery();
    string uriString = "https://www.google.com/calendar/feeds/" + username + "/private/full?ctz=utc";

    query.Uri = new Uri(uriString);
    query.StartTime = <time frame start>;
    query.EndTime = <time frame end>;

    EventFeed calFeed = service.Query(query);
    AtomEntryCollection entryColl = calFeed.Entries;
  2. Creating a calendar with tentative meeting times: ScheduleOnce cannot "lock" certain timeframes until the scheduling process is over. For this reason we create a tentative meetings calendar that can be used to see times that were proposed for a meeting.
    // Creating a calendar
    CalendarEntry calendar = new CalendarEntry();
    calendar.Title.Text = <calendar title>;
    calendar.Summary.Text = <calendar description>;
    calendar.TimeZone = <calendar timezone>;
    Uri postUri = new Uri("https://www.google.com/calendar/feeds/default/owncalendars/full");
    CalendarEntry createdCalendar = (CalendarEntry)service.Insert(postUri, calendar);
  3. Scheduling the meeting and sending the invitation via Google Calendar: When the meeting organizer schedules the meeting, a meeting entry is created in his calendar and meeting invitations are sent to all attendees.
    // Creating a meeting
    EventEntry entry = new EventEntry();
    entry.Title.Text = <meeting Title>;
    When eventTime = new When(<meeting startTime>, <meeting endTime>);
    entry.Times.Add(eventTime);
    Uri postUri = new Uri("https://www.google.com/calendar/feeds/" + username + "/private/full?ctz=utc");
    AtomEntry insertedEntry = service.Insert(postUri, entry);
Tip: Use Calendar API calls in a batch when possible to increase performance.

Using Documentation and Help Forums

Google provides very good documentation that can be accessed here. Marketplace listing and installation are very simple and instructions can be found on the Google Marketplace site. If you don't find what you need in the documentation, the first place to look is the Google Apps Discussion Groups. We were able to find everything we needed to build and integrate ScheduleOnce with Google Apps. The APIs and documentation made the job easy.

Check out ScheduleOnce at www.scheduleonce.com

2 comments:

Rasmus said...

Great add-on and very informative blog post!

We will try to use your tool along with this other reporting add-on for Google Calendar: http://www.youcalc.com/apps/1265969469500

With those two tools I believe Google Calendar can be used as a true enterprise scheduling & planning application.

software test consultan said...

This is great, 10x! I've been using google calendar as well as on my Milestone. With what you have posted here I can make it even better. :)