Filtered by Web development

Page 17

Reset

OpenID, Attribute Exchange, SReg, python-openid and Google

April 23, 2010
2 comments Web development, Python

OpenID logo I've learned a couple of things this week on deploying my first site to use a user friendly OpenID.

My first revelation was when I realized that Google and Yahoo! have solved the usability stumbling block that you can use them as providers without having to know a personally unique URL. For example, for Yahoo! it's just http://yahoo.com which means that you don't need to offer a cryptic URL form and you can just show it as a logo image.

The second thing is that Google's hybrid OpenID + OAuth isn't as complicated as it sounds. It's basically a light extension to the OpenID "protocol" whereby you say, "while you're at it, also give me a OAuth token please so that I can connect back into Google's services later". What's important to understand though is that if you use this you need to know the "scope". scope is a URL to a service. Google Docs is a service for example and you need to search the web to figure out what the scope URL is for that service.

The third revelation was when I understood the difference between Simple Registration Extension (SREG) and Attribute Exchange (AX). Basically, AX is a newer more modern alternative and SREG was the first one. AX is better but some OpenID providers don't yet support it. Google for example, only supports AX. Key to be able to support not just Google's OpenID but any OpenID is that you can request both AX and SREG and whichever one works will be returned.

The fourth thing that helped a lot to understand was the Google's OpenID has a bug in its implementation of Attribute Exchange. Actually, perhaps it's a deliberate design choice they've made but in my opinion a bad one. Unless you say you require email, firstname, lastname, country etc. it won't return it. If you use the if_available directive you won't get it. Another bug/bad design choice is that Google seems to not forward the country attribute. It can happily do first- and last name but not country even if the documentation claims so.

The fifth thing is that python-openid is a lot easier to work with than you think. You don't need to do any crazy network checks or callbacks. For initiating the challenge all you're effectively doing is creating a long URL. If you don't like the API methods python openid offers, just add your own with:


redirect_url += '&openid.ax.mode=fetch_request' # etc.

After so many years since OpenID arrived, I'm only now excited about it. It's tonnes easier to implement than OAuth and now it's actually really pleasant to use as an end user.

UPPER vs. ILIKE

April 19, 2010
4 comments Web development

I have a Zope web app that uses hand coded SQL (PostgreSQL) statements. Similar to the old PHP. My only excuse for not using an ORM was that this project started in 2005 and at the time SQLAlchemy seemed like a nerdy mess with more undocumented quirks than it was worth losing hair over.

Anyway, several statements use ILIKE to get around the problem of making things case insensitive. Something like the Django ORM uses UPPER to get around it. So I wonder how much the ILIKE statement slows down compared to UPPER and the indexed equal operator. Obviously, neither ILIKE or UPPER can use an index.

Long story short, here are the numbers for selecting on about 10,000 index records:


# ONE
EXPLAIN ANALYZE SELECT ... FROM ... WHERE name = 'Abbaye';
Average: 0.14 milliseconds

# TWO
EXPLAIN ANALYZE SELECT ... FROM ... WHERE  UPPER(name::text) = UPPER('Abbaye');
Average: 18.89 milliseconds

# THREE
EXPLAIN ANALYZE SELECT ... FROM ... WHERE  name ILIKE 'Abbaye';
Average: 24.63 milliseconds

UPPER vs. ILIKE

First of all, the conclusion is to use UPPER instead of ILIKE if you don't need to do regular expressions. Secondly, if at all possible try to use the equal operator first and foremost and only reside on the case insensitive one if you really need to.

Lastly, in PostgreSQL is there a quick and easy to use drop in alternative to make an equality operatorish thing for varchars that are case insensitive?

UPDATE 2014

There is an answer to the question just above: citext

Importance of public URLs and how enterprisecarsales.com gets it wrong

March 5, 2010
0 comments Web development

Importance of public URLs and how enterprisecarsales.com f's it up A friend of mine found a nice car she on www.enterprisecarsales.com so she copied the current URL from the address bar and emailed that to me. The URL was: http://www.enterprisecarsales.com/carsales/vehicleDetails.do?carIndex=1&vin=1GCHC24U36E112452 which by the look of it (notice the /vehicleDetails.do part of the URL) takes you to a page that says "Sorry, we are unable to complete your page request since the page you are trying to access no longer is available." How stupid is that? Come on, web developers made those kind of mistakes in 2001. Not 2010.

This means that people can't talk to each other about found matches on the site and this is something people want to do. Especially if you're going to spend $thousands on a car.

Come on Enterprise web team: install Django or something and give users what they want not your excuses.

Bookmarklet to replace the current domain with localhost:8000

January 17, 2010
1 comment Web development, Django

If you, like me, have various projects that do things like OAuth on Twitter or Google or you have a development site that goes to PayPal. So you're doing some Django development on http://localhost:8000/foo and click, for example, to do an OAuth on Twitter with an app you have there. Then Twitter will redirect you back to the live site with which you've set it up. But you're doing local development so you want to go back to http://localhost:8080/... instead.

Add this bookmarklet: to localhost:8000 to your browser Bookmarks toolbar and it does exactly that.

Here's its code in more verbose form:


(function() { 
   a = function(){
     location.href = window.location.href.replace(/http:\/\/[^\/]+\//,
            'http://localhost:8000/')
   };
   if (/Firefox/.test(navigator.userAgent)) { 
     setTimeout(a,0)
   } else {
      a()
   }
 })()

iPhone push notifications for Twitter with Prowl

October 25, 2009
1 comment Web development

iPhone push notifications for Twitter with Prowl Bruno Renié has written a nifty app:iPhone push notifications for Twitter with Prowl

With the power of Prowl it pushes a notification to your iPhone when someone mentions you on Twitter. You first need to install the Prowl app on your iPhone and then go to their website to get your notification key. Then, go to Bruno's site, sign in with your Twitter account (OAuth, so no password give-away) and badabing! you get instant notifications on your phone, for free, when someone mentions you.

If you're one of those people who use Twitter instead of instant messaging and have lots of mentions this might be excessive for you but if not it can be very useful if you are like me who is very slow to spot that someone has replied or mentioned your name.

Great work Bruno!

A user-friendly TinyMCE config

October 8, 2009
4 comments Web development

A user-friendly TinyMCE config When you enable TinyMCE you can either choose theme="simple" or theme="advanced". If you go for the simple you get one lovely little bar of buttons but it's missing the link button which is more important than most other buttons altogether. When you enable "advanced" you get three rows of buttons that makes you dizzy. I mean, should really be editing advanced tables in a WYSIWYG editor or mathematical equations?

Here's a config that I think works great. It's all in one row and it's got the bare minimum in terms of additional plugins (no extra downloads required). It's in Python but translates quite easily into Javascript:


TINYMCE_DEFAULT_CONFIG = {
   'plugins': "fullscreen,paste,autoresize",
   'theme': "advanced",
   'theme_advanced_buttons1' : "bold,italic,strikethrough,bullist,numlist,"\
                               "separator,undo,redo,separator,link,unlink,image"\
                               ",separator,cleanup,code,removeformat,charmap,"\
                               "fullscreen,paste",
   'theme_advanced_buttons2' : "",
   'theme_advanced_buttons3' : "",
}

The Secret to SEO Search Engine Optimization

August 20, 2009
0 comments Web development

"SEO is not about creating a website sausage overstuffed with key words and phrases. It’s all about creating relevant and compelling content that transforms you into a thought leader who can become a trusted provider That is ultimately how you convert visitors into buyers"

More optimization of Peterbe.com - CSS sprites

August 5, 2009
0 comments Web development

I have now made the menu images on this site into a CSS sprite. Basically, instead of loading 6 different images totaling 10Kb it now only needs 1 image which is 7Kb! The difference in filesize isn't the big win here but the reduced number of requests is the big deal.

The number one tip from the Yahoo! Performance people is reducing the number of requests and this is what I've done.

To generate the sprite image I use the CSS Sprite Generator and then fiddled it a bit to make it work for this site. Thanks guys!

The major drawbacks of CSS Sprite images isn't really technical but it's just that it's an optimization hack. The next time I need to change any of the images I have to reapply the hack and there's a risk that by the time I need to get back into it I will have forgotten how to do it or where to go to do it. Anyway, I'm really pleased with the performance of this site now.

Getting uploadify to work

July 17, 2009
11 comments Web development

Uploadify is a great tool. I'm using it so that people can mass upload photos for a photo gallery app I'm working on. This afternoon I've spent about 3-4 hours trying to get it to work on Windows (IE, Chrome, Firefox). It wasn't easy but I think I got it working in the end.

Pitfall no 1 (easy)

The Javascript code that "wraps" the "uploader.swf" had a bug in how it calculated the installed Flash version in IE (only tested in IE6). So I fixed that and will shortly send a patch to the uploadify.com.

Pitfall no 2 (hard)

I've got nginx on the server passing requests to a Django daemon via FCGI. For some obscure reason, on Windows, if the file uploader.swf was served as a static file directly from nginx it wouldn't work and I would get 403 errors that are never explained in the nginx error log or anything. So I changed it to let Django serve up the uploader.swf file which obviously sets headers differently and then it worked.

Headers when served directly by nginx:


HTTP/1.1 200 OK
Server: nginx/0.6.34
Date: Fri, 17 Jul 2009 17:01:09 GMT
Content-Type: application/x-shockwave-flash
Content-Length: 18659
Last-Modified: Wed, 08 Jul 2009 12:29:52 GMT
Connection: keep-alive
Accept-Ranges: bytes

Headers when served from Django (django.views.static.serve):


HTTP/1.1 200 OK
Server: nginx/0.6.34
Date: Fri, 17 Jul 2009 17:01:03 GMT
Content-Type: application/x-shockwave-flash
Connection: keep-alive
Last-Modified: Wed, 08 Jul 2009 12:29:52 GMT
Content-Length: 18659
Vary: Cookie

Pitfall no 3 (super complex)

It was working in Firefox Linux, Safari Mac, Firefox Mac but not IE6 Windows, Firefox Windows or Chrome Windows. This despite having the latest (and same as Linux) version of Flash (10.0.22.x)!

Solution: In Internet Explorer, click on Options and delete the cookies, temporary Internet files and Clear History (for good measure). Now it works!!

It's been a hell of a journey but now it's crossed. Let's hope I can save some other poor sucker a couple of hours by making this blog available.

UPDATE

ow it's stopped working again. Works in Opera Windows but not IE 8 in windows 7. Grr...!

UPDATE 2

I've completely abandoned Uploadify now and instead gone for Swfupload which actually works really well.