Alain Hufkens {Rich Interactive Applications Developer}

26Jun/097

Timy – Time tracking in 7th gear using Adobe AIR

timy_logoRecently my company (Nascom) released Timy beta, an Adobe AIR desktop client that we have been using internally for more than a year now. The application has a long history and was initially built to gain knowledge about Adobe AIR and to make time tracking using Basecamp easier to do. I don't know if any of you use Basecamp for time tracking but it is not the easiest thing to do. Probably most of you use Basecamp for the project management and collaboration features, but you can also use it for time tracking. The web interface doesn't provide you with a quick overview of projects and todo items.

The main idea was that if we had a simple way of adding hours to a project for a certain day, we could loose less time filling in our time sheets. Development started before Adobe AIR was released and at the time this seemed the perfect technology for such an application. We could leverage the power of Adobe AIR because it uses SQLite for local data, shows notifications, and runs in the system tray so that we don't forget to fill in out time sheets. The application is built using Flex 3 and the Cairngorm framework. Credits for the design of the application go completely to Kristof who did a great job.

One of the biggest reasons for using Adobe AIR, is that the Basecamp API doesn't allow you to get the data that's necessary for the Timy projects tab in one API call. You need to first get all the projects, and then for all the projects the to-do lists, and then you can get the to-do items. If you work in a company that does a lot of projects this can take a while to retrieve. That's why the application synchronizes this data (projects, to-do lists and to-do items) with a local cached SQLite database. Only when the app detects that there is a new (or removed) project it asks the user to synchronize again. Does this make any sense? Well it did for us and that's why we released this application as it is. If you might find a use for it or not, it was still fun to develop.

We also track the usage of the AIR application in real-time itself using Pubblegum. So if you see some extra outgoing API calls, then this is what is going on. We don't log any sensitive data, only basic actions like: open, error, sync, login and close. We also send along the version number to see which versions are running in the field. You can compare it with Google Analytics for Adobe AIR applications with offline support.

Timy screenshotBut before you get all enthusiastic and start installing the app, you should now a few things. Timy is a Basecamp client, so if you are not a Basecamp user then Timy is of no use for you. You also need to use Basecamp in  certain way, and enable time tracking on your to-do lists. It's pretty easy to do, but if you don't work like this, there will be no tasks for your users. Also important to know is that we see the to-do item for a project as a profile (ex. Development, Design, Html, ...) and not individual tickets, tasks or to-do items that you can check off. This is very important. But you can still use both normal to-do items and time tracking enabled to-do items because Timy only looks at time tracking enabed to-do lists.

You can read more about how to configure your Basecamp projects in the "get started" section, and you can find more info on how to use Timy in the "documentation" section of the site. I don't normally read these kind of pages either, but I would strongly suggest to read the get started page. If you have any feedback for the app please add it to the feedback forum or drop me a comment here.

Filed under: air, flex 7 Comments
23May/091

Silverlight and Basic Authentication

After installing Visual Studio 2010 beta 1 I decided to play around with Silverlight 3 and the new IDE. What better example to try out than connecting a Silverlight client to the Basecamp REST API. But again like the Twitter API, the Basecamp API uses Basic Authentication (see my previous post: Flex HTTPService and Basic Authentication) and also in the case of Silverlight, it appeared to be a problem.

The first thing I tried was adding the Authorization header to the Webclient, like you can do in Actionscript.

string url =
    String.Format("https://{0}/{1}", basecampUrl, "projects.xml");
var webclient= new WebClient();
Byte[] authbytes =
    System.Text.UTF8Encoding.UTF8.GetBytes("username:password");
webclient.Headers["Authorization"] =
    "Basic " + Convert.ToBase64String(authbytes);
webclient.DownloadStringCompleted += downloadStringCompleted;
webclient.DownloadStringAsync(new Uri(url));

This didn't work because the Authorization header can't be set through code because it is restricted. Check this page for the list of restricted headers. Some can be set through a specific property, but not the Authorisation header. The error message I got was this:

System.ArgumentException:
The 'Authorization' header cannot be modified directly

Then I checked out Silverlight 3 and discovered the Credential property. You can set the Credential property to an instance of a NetworkCredential object.

string url =
    String.Format("https://{0}/{1}", basecampUrl, "projects.xml");
var webclient= new WebClient();
webclient.Credentials = new NetworkCredential("username", "password");
webclient.DownloadStringCompleted += downloadStringCompleted;
webclient.DownloadStringAsync(new Uri(url));

But too bad, the exception I got this time was even more strange:

System.NotImplementedException:
The property is not implemented by this class

Seems like there is still something missing in the beta 1 version of Silverlight 3, so please Microsoft fix this or just remove the property if it's not implemented.

So this means that the only way to get the Basic Authentication working from Silverlight at the moment is writing an extra server-side proxy class that delegates the calls and does the authentication. Or maybe there is another trick in the Silverlight Webclient class.

Filed under: silverlight 1 Comment
14May/093

Retrieve Basecamp data with BasecampAS3Lib

One of the projects I am currently working on is an open source Actionscript library that wraps the Basecamp REST API in an easy to use AS3 classes. The project is called BasecampAS3Lib an can be found on Google Code. The project is still in development and I did some serious refactoring yesterday.

At this point the services can only retrieve data from Basecamp and you can already experiment with the ProjectService, CategoryService and TodoListService classes. The other services still need to be implemented. But this post will give you a sneak peak on how simple it can be to retrieve data (in this case project data) from Basecamp with this lib.

NOTE: This code only works in an Adobe AIR application (see below for more details why).

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:basecamp="net.hufkens.basecamp.*"
  xmlns:services="net.hufkens.basecamp.services.*"
  layout="absolute"  viewSourceURL="srcview/index.html">
 
  <mx:VBox width="100%" height="100%">
    <mx:HBox width="100%">
      <mx:Label text="url:"/>
      <mx:TextInput id="apiurl" width="100"/>
      <mx:Label text="username:"/>
      <mx:TextInput id="username" width="100"/>
      <mx:Label text="password:"/>
      <mx:TextInput id="password" width="100"/>
      <mx:Button label="get projects"
        click="getProjects()"/>
    </mx:HBox>
    <mx:DataGrid dataProvider="{projects}"
      width="100%" height="100%"/> 
  </mx:VBox>
 
  <basecamp:BasecampAPI id="api"
    url="{apiurl.text}"
    username="{username.text}"
    password="{password.text}"/>
 
  <mx:ArrayCollection id="projects"/>
 
  <mx:Script>
    <![CDATA[
      import net.hufkens.basecamp.events.BasecampEvent;
     
      private function getProjects():void {
        api.projectService.addEventListener(
          BasecampEvent.GET_LIST, handleGetList);

        api.projectService.addEventListener(
          BasecampEvent.FAIL, handleFail);

        api.projectService.getList();
      }
     
      private function handleGetList(event:BasecampEvent):void {
        projects = new ArrayCollection(event.data as Array);
      }
     
      private function handleFail(event:BasecampEvent):void {
        Alert.show(event.data as String);
      }
     
    ]]>
  </mx:Script>
 
</mx:WindowedApplication>

However there is still an issue with the authentication. Apparently using basic authentication from a Flash/Flex application is not that trivial as it would sound. A while ago I wrote a blog post about this (read it here), but this approach only works when you run it from an AIR application. The same code doesn't work when running from a url on a web site.

So, if you have any suggestions or a solution for the basic authentication issue please let me know.

Filed under: air, flex 3 Comments
17Mar/090

Flex HTTPService and Basic Authentication

For an internal project I created an Adobe AIR application that connects to the Basecamp API. We have been using the application since the launch of Adobe AIR. Back then I had a problem connecting to the API using the HTTPService, because the combination of Basic Authentication and the https protocol was not supported. After several unsuccessful experiments I decided to go for an approach that uses a PHP Proxy on the server that delegates the calls to the Basecamp API. However the downside of this approach is that this setup needs extra configuration and a server-side deployment.

This week I got the chance to pick it up again and I stumbled upon this forum post on the Basecamp Forum. I found this piece of code posted on Verveguy's blog. And it actually did the trick.

private function addAuthHeader(service:HTTPService,
                     username:String, password:String):void
{
    //add the header to request
    var enc:Base64Encoder = new Base64Encoder();
    enc.encode(username + ":" + password);
    service.headers["Authorization"] = "Basic " + enc.toString();
}

For everybody who needs to connect a Flex application to an API that uses https in combination with Basic Authentication, here is the solution. All credits to the original blog post.

Filed under: air, flex No Comments