Spring cleaning is complete and the driving code behind bestinclass.dk is now being released as opensource. With it you can generate a static site, import a wordpress blog, emit feeds (atom) and much much more.
Last month I did a remake of BestInClass.dk and afterwards I was very tied up preparing for the Conj Labs session here in June. But now that we're catching up, I figured I would clean the code-base and release it.
One big win to this approach is that you can fiddle with the backend all you want and once you're ready to update, just rsync the code to the server and call restart on the jetty script. The only downtime your users will experience is between the closing of the socket and until Jetty is up again, and only users who are clicking the comment button at that exact time will notice!
One of the things which can come in handy when you're rapidly testing web-handlers, is Moustache. I used it heavily during the first days of development and I've left the webview.clj file in the repo, as a reminder to others not to let your prototyping grow out of hand. If you want to do some prototyping which mimics what I did, then feel free to use it otherwise just remove it.
You might be wondering how the backend is secured, since there's no standard auth lib available for ring/moustache. The backend opens an interface which only answers to calls from 127.0.0.1, meaning the webserver it self. To reach it you have to get through a reverse proxy pass, which filters the reponses based on certain criteria, which amount to this: If you're not me, you're not getting proxied. So almost all security is at the webserver level.
The primary bestinclass.clj file was used by me when I deployed bestinclass.dk for the first time. Its a one off event since it goes through all of the :WP:POST entries in the Wordpress backup file and generates the html version of those posts. Afterwards, the static pages "Forside", "Services" etc are generated and finally the atom feed is generated. All of these emissions of html/xml call templates or snippets found in the templates.clj file. The file should more approriately be used to start the admin interface now, but adjust it to your needs.
While the generation of the site shows of Enlive better half namely "templates" then the Wordpress import module shows of "selections" or scraping. Some of the selectors are a little complex and I must admit I've consulted with both Christophe and David Nolen to arrive at the result. However it stands as a very good demo of just how powerful Enlive is.
The backend features as not-so minimalistic editor:
There's also some statistics and an interface for comment moderation. Since I added the custom captcha I have not received one single spam comment - not one! If you want to test the comment interface yourself without running the frontend through a webserver, you can post like this:
$ curl -d "url=someurl&name=Lau&email=mymail&captcha=10&cid=0&comment=hi" http://127.0.0.1:8080/cmt/
The url is only used to determine which file to write the comment in, and it poses a potential security hole as you could manually post to /../../../some-config and then really make my life miserable. So it checks if you're doing any such thing and if its determined that you're trying to crack my server, the dogs are dispatched immediately. If you need to test with something that has spaces and linebreaks just run that string through java.net.URLEncoder/encode and paste it to curl.
If the comment comes through with the correct captcha answer and the URL isn't malformed/manipulated, then the server sends me an email (please change the recipient on your local installation). It does so via a postfix server running on "localhost" - any smtp server will do. See email.clj for more details.
There's still work to be done. Name the load-times on the admin interface needs to be improved (its not hard) and the editor should be integrated in the admin interface. As it is I go to /editor and once I've completed the entire post I browse to the /admin interface (waiting once again for the stats) and publish.
I'll let the code speak for itself. If you like this approach to webapplications, please feel free to use the code, you can find it here: Github
If you would like to get an update when I post on this website, either subscribe to the RSS feed or follow me on Twitter.