Simon Fell > Its just code > June 2008

Thursday, June 26, 2008

Sometimes full blown 2 way sync is just overkill, for some people just having a read only copy of their calendar in iCal is all they want, fortunately this is pretty straightforward, iCal supports subscribing to iCalendar feeds, and conveniently your Mac includes a copy of Apache httpd, so can easily run perl, python etc in response to a request. Throw in a library for accessing the API, and you have all the ingredients needed. I put this together in Python using Beatbox, it makes API calls to login and to query events, and to generate an iCalendar formated response, You then subscribe to the url on your local Mac in iCal to show the data in iCal with the rest of your calendars.

  • Download the code, this has the 2 files for beatbox, and the third is the iCalendar generator.
  • Unzip this and drop the 3 files into your /Library/WebServer/CGI-Executables folder.
  • From System preferences -> Sharing make sure that Web Sharing is turned on.
  • Quickly test it in safari, goto http://localhost/cgi-bin/ if everything works, you should see something that starts like
    PRODID:-//PocketSoap//pyCal 1.0//EN
    X-WR-CALNAME:Salesforce calendar : Simon Fell
  • Goto iCal, goto the calendar menu and pick subscribe, paste the URL from safari into the URL box, and then in the resulting dialog, pick how often you want it to auto-refresh (I'd suggest no more often than once a hour).

That's it!, you're good to go, you should have all your upcoming events now showing in iCal.

SF3 Is now available, if you're on a older version, you'll get prompted to upgrade next time you restart it. This adds a new option to get a prompt before applying any changes to, useful for spotting when a sync is going to change/delete more data than you were expecting.

Also included is support for multi-day all day events, a new feature added to in the summer '08 release, now these will get correctly mapped between Salesforce and iCal.

Sunday, June 8, 2008

There's no shortage of bad coffee choices next to Moscone, but if you can drag yourself away from all the conference action and walk one block, (mint plaza, mission & 5th) you can avail yourself of some of the best coffee in the bay area, or indeed the west coast. The Blue Bottle cafe opened earlier this year in Mint Plaza, go check it out, you won't be sorry.

Thursday, June 5, 2008

Unless you've been living under a very large rock, you know its WWDC next week and everyone is hopped up on predictions of OSX 10.6 and 3G iPhones with GPS & espresso machines built in, and of course the release versions of iPhone 2.0 and the SDK. Besides all the iPhone news everyone is waiting for, I'd like to see Apple step up to the plate on virtualization, and let us run OSX virtualized, its a royal pain in the ass to support OSX apps because the only way to test on multiple versions of the OS is to maintain a bunch of different installs of the OS and boot between them, how 1990's. And it not even like you can get away with just a 10.4 and a 10.5 install, there's enough differences between 10.5.0, 10.5.1, 10.5.2 and 10.5.3 that you'd really want to test on at least some of them.

Quick API tip, most of the API requires you to know both the ID of a record, and its type (e.g to update it, or to retrieve its field values). In most cases it pretty easy to get that, but where most people get tripped up is on polymorphic foreign keys (e.g. whoId on task), the trick is to remember the thing at the end of the relationship can tell you its type, so instead of using this query, then being left trying to work out what type the whoId is,

select id, whoId from task
instead use SOQL-R, and use this query, now you will know what type the whoId is without any further shenanigans (like calling describeSObject on everything and matching the keyprefix which is horribly slow way to do it)
select id,, who.Type from task
The follow on is that it then becomes easy to run queries that find all tasks ascociated with contacts, it's just
select id,, who.Type from task where who.Type='Contact'