12
Jan
09

Integrating Gravatar with Castle MonoRail

As part of my experimental Castle MonoRail project that I mentioned last time. I now wanted to allow users to include an image (avatar) within their profile. Obviously I could have just allowed them to upload an image, store it and then shown it when required. But I thought I’d integrate with Gravatar instead.

Gravatar is basically a free service where anyone can store an avatar image against an email address. They provide a very simple API for us developer types to integrate with given a user’s email address. So without further ado, here is what I did:

1. I signed up for a Gravatar account and uploaded an image ready for testing.

2. I created a test (TDD style) for a GravatarHelper class that would at first just return the correct image URL for an email address. I took the test data from their documentation so I knew it was correct:

[TestFixture]
public class When_using_the_gravatar_helper
{
    [Test]
    public void Should_build_a_basic_image_url()
    {
        var gravatar = new GravatarHelper();
        string url = gravatar.Url(" iHaveAn@email.com ");

        Assert.That(url, Is.EqualTo("http://www.gravatar.com/avatar/3b3be63a4c2a439b013787725dfce802.jpg"));
    }
}

OK, so pretty straightforward there then. The email address is of mixed case and has spaces around it on purpose as the documentation specifies that emails need to be trimmed and lowercased before hashing.

3. Now I have my failing test, I went right ahead and started implementing it:

public class GravatarHelper : AbstractHelper
{
    private const string PROTOCOL = "http";
    private const string DOMAIN = "www.gravatar.com";
    private const string PATH = "avatar";
    private const string EXTENSION = "jpg";

    public string Url(string email)
    {
        email = email.ToLower().Trim();

        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] hash = md5.ComputeHash(Encoding.ASCII.GetBytes(email));

        var hashAsHex = new StringBuilder();
        Array.ForEach(hash, b => hashAsHex.Append(b.ToString("X2")));

        return string.Format("{0}://{1}/{2}/{3}.{4}", PROTOCOL, DOMAIN, PATH, hashAsHex, EXTENSION).ToLower();
    }
}

Again, no rocket science here. I just lowercase and trim the email address then hash it using the built-in .NET MD5 hash provider. Then I have to convert each byte in the hash into hex and add it to a string. Lastly I return the URL that has been built up from the various parts (and lowercased for good measure).

4. Next, just add the helper to my controller:

[Helper(typeof(GravatarHelper), "gravatar")]
public class AccountController : SmartDispatcherController
{
    ...
}

5. Then the simple task of using the helper in my view (not my real email):

<img src="$gravatar.url('someone@somewhere.com')" />

And hey presto, my Gravatar of my son appeared on my page, wahoo:

gravatar

Now that is all very good, but there are some extra parameters that the Gravatar API support. These are size, rating and default (in case the email address isn’t registered with them). I also wanted the helper to generate the image tag for me. So I went about creating a new helper test:

[Test]
public void Should_build_an_image_url_inside_an_image_tag_with_parameters()
{
    var gravatar = new GravatarHelper { ServerUtility = new StubServerUtility() };
    IDictionary parameters = new Hashtable
                                 {
                                     { "size", "48" },
                                     { "default", "http://example.com/images/example.jpg" },
                                     { "rating", "g" }
                                 };
    string tag = gravatar.Image(" iHaveAn@email.com ", parameters);
    Assert.That(tag, Is.EqualTo("<img src=\"http://www.gravatar.com/avatar/3b3be63a4c2a439b013787725dfce802.jpg?size=48&default=http%3a%2f%2fexample.com%2fimages%2fexample.jpg&rating=g\" alt=\"Gravatar\" />"));
}

I’m using an IDictionary here so that I can leverage the support for it in NVelocity. So about these parameters: The size parameter is the size in pixels that you would like the image (1 to 512) which defaults to 80. The default parameter is a URL of an image in case the email address supplied isn’t known by Gravatar. The rating parameter can be g, pg, r or x. Also notice in the test the need to set the ServerUtility property of the helper, I just using the StubServerUtility provided by Castle.

Now for the implementation:

private const string IMAGE_TAG_FORMAT = "<img src=\"{0}\" alt=\"Gravatar\" />";

public string Url(string email, IDictionary parameters)
{
    string url = Url(email);
    string queryString = CommonUtils.BuildQueryString(ServerUtility, parameters, false);

    return string.Concat(url, "?", queryString);
}

public string Image(string email, IDictionary parameters)
{
    return string.Format(IMAGE_TAG_FORMAT, Url(email, parameters));
}

The eagle-eyed amongst you will notice that I’ve added an overload to the Url method as well that supports parameters (I wrote a test for this first, so don’t panic). So you can now either create a url with parameters or a full image tag. So now in my view I can do this:


$gravatar.image("someone@somewhere.com", "%{size='48', rating='g', default='http://example.com/default.jpg'}")

That about wraps it up for now. I’ve committed all my code into my Google Code repository, so feel free to have a look: http://code.google.com/p/andypike/

kick it on DotNetKicks.com


4 Responses to “Integrating Gravatar with Castle MonoRail”


  1. January 13, 2009 at 9:44 am

    Cool stuff πŸ™‚

    I’d also consider adding overloads to the .Image() method, for the size, rating and default, for the sake of view engines that can benefit from intellisense (shameless plug for AspView …)

  2. January 13, 2009 at 12:16 pm

    nah. thank you for sharing your experiences with the public.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s


Twitter

My Archives

My Categories


%d bloggers like this: