Simon Fell > Its just code
Thursday, June 26, 2008
sfical.pySometimes full blown 2 way sync is just overkill, for some people just having a read only copy of their salesforce.com 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 Salesforce.com 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/sfical.py?un=user@foo.bom&pwd=SomePassword if everything works, you should see something that starts like
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//PocketSoap//pyCal 1.0//EN X-WR-CALNAME:Salesforce calendar : Simon Fell METHOD:PUBLISH BEGIN:VEVENT
- 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 v0.6SF3 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 Salesforce.com, 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 Salesforce.com in the summer '08 release, now these will get correctly mapped between Salesforce and iCal.
Sunday, June 08, 2008
WWDC Coffee optionsThere'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 05, 2008
WWDCUnless 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.
who.typeQuick Salesforce.com 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.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.id, who.Type from task where who.Type='Contact'
Saturday, May 03, 2008
Metadata API (more)I discovered a new Salesforce related blog today, and noticed that they spread the seeming popular meme that the metadata API doesn't work on standard objects, so just clarify that that's wrong, here's a .NET example that adds a new custom field to the standard Account object.
using System;
using System.Collections.Generic;
using System.Text;
namespace metadata
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("useage: metadataDemo username password");
return;
}
MetadataCreator mc = new MetadataCreator(args[0], args[1]);
mc.Create();
}
}
class MetadataCreator
{
private metaforce.MetadataService ms;
private sforce.SforceService ss;
public MetadataCreator(String username, String password)
{
ss = new sforce.SforceService();
sforce.LoginResult lr = ss.login(username, password);
ss.Url = lr.serverUrl;
ss.SessionHeaderValue = new sforce.SessionHeader();
ss.SessionHeaderValue.sessionId = lr.sessionId;
ms = new metaforce.MetadataService();
ms.Url = lr.metadataServerUrl;
ms.SessionHeaderValue = new metaforce.SessionHeader();
ms.SessionHeaderValue.sessionId = lr.sessionId;
}
public void Create()
{
metaforce.CustomField cf = new metaforce.CustomField();
cf.description = "Favorite fruit";
cf.fullName = "Account.favFruit__c";
cf.label = "Fav Fruit";
cf.type = metaforce.FieldType.Text;
cf.length = 25;
cf.lengthSpecified = true;
metaforce.AsyncResult r = ms.create(new metaforce.Metadata[] { cf })[0];
while(!r.done) {
System.Threading.Thread.Sleep(r.secondsToWait * 1000);
r = ms.checkStatus(new string[] { r.id })[0];
}
if (r.state == metaforce.AsyncRequestState.Error)
Console.WriteLine("Error : {0} {1}", r.statusCode, r.message);
else {
Console.WriteLine("Done, added new field to Account");
}
}
}
}
Thursday, March 06, 2008
SFFS![]() |
About a year ago I posted about sfdcFuse, a command line utility that exposes the Document repository in Salesforce.com as a mountable volume using MacFUSE. Unfortunately this version doesn't work on Leopard, so I've been working on a Leopard version, and at the same time, getting rid of the command line interface and putting a regular cocoa front end on it. The result is SFFS (the SalesForce File System). Much like the earlier version, this exposes a read-only copy of your document repository as a mounted volume on your Mac. You get my standard UI for login, complete with keychain support, and auto-updates via Sparkle. Its available under the open source BSD license, everything is over on the Google code project. |
Monday, February 18, 2008
SF Cubed v0.53I just released this, it fixes a problem with all day events not picking up date changes from Salesforce.com, and addresses some weirdness relating to filtering on 10.5.2 (which would manifest itself as SF3 saying it picked up local changes, but that it didn't appear to change anything in Salesforce.com). I'm working entirely out of the Google code project now, so you can see source code changes for specific issues, issues come and go in the issue tracker, and the sparkle auto-updater is now pulling builds from the google code site. Everything seems to be working just fine.
Sunday, February 17, 2008
Maildrop goes open sourceHot on the heals of SF3, Maildrop is now open source as well, checkout the source, log bugs, enhancement requests etc all over at the project home page @ Google code. My thanks to Ron and the ADN crew for helping organize this.
Thursday, February 14, 2008
10.5.2The Core Data file truncation bug I previously mentioned is fixed in 10.5.2.
Sunday, February 10, 2008
SFCubed now open sourceWith the 0.52 release of SF3 I made it open source under the BSD license. Rather than host everything myself, which is how I've handled previous open source projects of mine, (sourceforge looked to be on its last legs for quite a well, but is still going) I've decided to try out the Google code project hosting. Everything is over there, source code in SVN, an issue tracker that i loaded up with all the bugs and feature requests i know about, and there's a wiki that contains most of the content from my own SF3 page. Share & Enjoy.
Friday, February 08, 2008
SF CubedFor those folks that have ran into iCal sync problems on Leopard, try this build, let me know how you get on. (this also includes a lot of fixes for contact sync where your AB contact have more data than salesforce supports, e.g. multiple work phone numbers). I've also decided to open source SF3, as i just don't have the time to move it forward fast enough, the complexities of the sync and data mapping process/problems means you really can't work on it in little chunks of time like i can for the other apps. This should give the folks that are in need of more features and/or specific changes for their setup a chance to get what they need done.
Sunday, February 03, 2008
SoqlX superbowl editionThere's a new version of SoqlXplorer available, this version requires Leopard, it has an updated UI, support for displaying child queries (double click on the magnifying glass icon), a recent query list, and a few other bits'n'peices.
Thursday, January 31, 2008
Metadata API from .NETA few people have been asking for a complete example of using the metadata API from .NET, If you've using the regular enterprise/partner API, then the patterns should look familiar. One wrinkle for .NET is the whole fooSpecified mess, this is more apparent in the metadata API because most of the fields aren't strings.
I created a new project in VS.NET 2005, imported the enterprise WSDL (as sforce) and imported the metadata WSDL (as metaforce), the code makes a login call with the enterprise API, creates a stub for the metadata API, configuring the sessionHeader and Url from the login result (just like for the regular enterprise stub). then goes on to setup a CustomObject structure and passes it to create. One difference to the enterprise API is that the process is async, so you get back an AsyncResult structure that indicates its current state, a guess at how long to wait before checking its state again and so on, so we sit in a loop (with the specified waits) until its done. If the object was created, then we call describeSObject on the enterprise API to check that it really did do something, here's the code.
using System;
using System.Collections.Generic;
using System.Text;
namespace metadataDemo
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("useage: metadataDemo username password");
return;
}
MetadataCreator mc = new MetadataCreator(args[0], args[1]);
mc.Create();
}
}
class MetadataCreator
{
private metaforce.MetadataService ms;
private sforce.SforceService ss;
public MetadataCreator(String username, String password)
{
ss = new sforce.SforceService();
sforce.LoginResult lr = ss.login(username, password);
ss.Url = lr.serverUrl;
ss.SessionHeaderValue = new sforce.SessionHeader();
ss.SessionHeaderValue.sessionId = lr.sessionId;
ms = new metaforce.MetadataService();
ms.Url = lr.metadataServerUrl;
ms.SessionHeaderValue = new metaforce.SessionHeader();
ms.SessionHeaderValue.sessionId = lr.sessionId;
}
public void Create()
{
metaforce.CustomObject co = new metaforce.CustomObject();
co.deploymentStatus = metaforce.DeploymentStatus.Deployed;
co.deploymentStatusSpecified = true;
co.description = "My Custom Object created from .NET";
co.fullName = "DotNetCustomObject__c";
co.label = "DotNet Custom Object";
co.pluralLabel = "DotNet Custom Objects";
co.sharingModel = metaforce.SharingModel.ReadWrite;
co.sharingModelSpecified = true;
co.nameField = new metaforce.CustomField();
co.nameField.type = metaforce.FieldType.Text;
co.nameField.label = "The Name";
co.nameField.length = 100;
co.nameField.lengthSpecified = true;
metaforce.AsyncResult r = ms.create(new metaforce.Metadata[] { co })[0];
while(!r.done) {
System.Threading.Thread.Sleep(r.secondsToWait * 1000);
r = ms.checkStatus(new string[] { r.id })[0];
}
if (r.state == metaforce.AsyncRequestState.Error)
Console.WriteLine("Error : {0} {1}", r.statusCode, r.message);
else {
Console.WriteLine("Created customObject {0}, calling describeSObject now", co.fullName);
sforce.DescribeSObjectResult d = ss.describeSObject(co.fullName);
Console.WriteLine("DescribeSobject for {0} ({1})", d.name, d.label);
foreach(sforce.Field f in d.fields)
Console.WriteLine("{0}\t{1}", f.name, f.type);
}
}
}
}
And here's the output from a running it
Created customObject DotNetCustomObject__c, calling describeSObject now
DescribeSobject for DotNetCustomObject__c (DotNet Custom Object)
Id id
OwnerId reference
IsDeleted boolean
Name string
CreatedDate datetime
CreatedById reference
LastModifiedDate datetime
LastModifiedById reference
SystemModstamp datetime
Creating customFields is just as easy, just remember to specify the fully qualified fieldname as its fullName, e.g. if you wanted a new field on your custom object co__c, you set the name to be co__c.newField__c, or if you wanted a new custom field on Account, it'd be Account.newField__c. Share and Enjoy.
Wednesday, January 23, 2008
Office 2008I seem to be collecting Office suites that don't quite do what i want. I upgraded to iWork '08 when it came out because i was looking for something better than Excel 2004, which is bloated and sluggish (even on my 4 core mac pro). However Numbers has no way as far as i can see to get external data into it, no support for AppleScript, and no equivalent to Excel's Web Query feature, so its largely sat on the sidelines gathering dust. So, my copy of Office 2008 turned up last week, I figured the new Intel native version would at least be snappier than its rosseta stone older sibling, but no, somehow it feels about as sluggish as the previous version. Now, i was expecting the loss of VBA macro's but i didn't realize that they'd completely abandoned any document integration at all, yes I can write apple script to manipulate spreadsheets, but these scripts aren't stored in the document, i can't assign an applescript to say a button in the document, there doesn't seem to be any sort of event integration, so i can run scripts on save, or load. I now have a single menu item with a (potentially) bucket-load of apple scripts and I've got to remember which one goes with which document. And just to rub salt in the wound, Web Queries seem to be broken, you can create new one's fine, but goto do a refresh and you'll get the cryptic and unhelpful message "selection can contain a single cell only", nice, you should be able to return broken software. Guess I'm stuck with Excel 2004 for a while longer, ho hum.

