Your browser is very old. You might enjoy surfing the web more if you used something newer like:

Google Chrome

Even Firefox would be OK.

If you're being forced at gunpoint to use Internet Explorer, you should at least upgrade it. Version 8 is tolerable and 9 will be OK when it comes out.

Posts from October 2008

Comment Engine: Round 2

The basic Comment functionality seems to be working on this site (not than anyone has actually left any real comments yet).

Working with the Users API

I’m in the midst of working on an admin page for myself so I can delete comments, add site API keys, etc. This lead me towards dealing with authenticating admin users. Of course, Google has this all taken care of already thanks to the Users API.

Here’s the code for handling the admin page for the Comment Engine:

class AdminPage(webapp.RequestHandler):
    def get(self, action):
        if action == 'logout':
            self.redirect(users.create_logout_url('/admin/'))

        user = users.get_current_user()

        if user:
            if users.is_current_user_admin():
                self.response.out.write('I am an admin!')
            else:
                self.response.headers['Content-Type'] = 'text/plain'
                self.response.out.write(user.email() + ' is not a valid Administrator');
        else:
            self.redirect(users.create_login_url(self.request.uri))

Pretty easy, huh?

Here’s how it works

  1. Handle the URL /admin/logout by logging out the current user
    • The user is redirected back to the admin page after logout
  2. If we’re not logging out, grab the current user and see if it’s actually a valid object
  3. If the current user isn’t a valid object, redirect to the login url
    • This hands the user off to logging into Google Accounts which means that Google is handling all of the annoying stuff with account creation/management.
    • After they log into Google Accounts, they come right back to the admin page
  4. Once the user is logged in, check to see if they’re an Admin for the application
    • Again, Google handles this via the Developer section of the AppEngine application configuration page.
    • You just add a list of Google Accounts that are allowed to administrate the application.

And, voila! I have an admin page that, currently, only I have access to.

Weirdness with Indexes

I did run into one bit of strangeness related to Indexes.

I’ve been doing development on a couple of different machines (a desktop & a laptop). I’d noticed the index.yaml file but hadn’t really paid much attention to it since it seemed to be auto-generating what it needed and I wasn’t having any issues.

Until last night.

Suddenly, out of no where, a bunch of my previous GET queries started throwing NeedIndexError exceptions.

I spent some time poking around and noticed that my application config on appgengine.google.com only listed one Index for the application while my local copy of index.yaml actually had 4 auto-generated Indexes listed.

I did another update to send my local copy of the app up to the App Engine but that didn’t seem to be updating the Indexes on the live app.

In the end, I had to manually move all of my Index out of the AUTOGENERATED area of index.yaml.

Once I’d done that and resynced the app, everything started working again.

Comment Engine: Round 1

Last week, I mentioned that I was working on a comment engine which uses the Google App Engine for the back end. While the plan is for it to support multiple sites, its main purpose is to be used here on this site.

After some on-and-off hacking over the weekend, I have something that works reasonably well. The App Engine back-end seems to be working perfectly. The front-end (which will sit on this site) is going to be PHP & Javascript.

Here’s what works

  • Comments can be submitted and are saved to the Google Datastore.
    • The comment is submitted as JSON-encoded array.
    • The array contains the following fields: author, email, comment, pagename, sitename, & sitekey.
  • Every comment is keyed with a site name, page name, & a unique id.
  • A unique identifier is required to submit a comment. This should prevent comments from being submitted from outside of the hosting page. We’ll see how well this part works once it goes live.
  • Comments can be retrieved in the following way (all return values are in JSON format)
    • /get/<sitename> returns all comments for an entire site.
    • /get/<sitename>/<pagename> returns all comments for the specific page on a site.
    • /get/<sitename>/<pagename>/<id> returns a single comment for a page.

What’s left to do?

  • Need a way to moderate comments. Deleting comments is the most important. The problem is dealing with the authentication so that only authorized users can moderate.
  • Need a better way to support multiple sites & API keys. Right now, there’s just one sitekey for this site and it’s hard coded.

What I need to do is sit down and figure out the Users API, create an admin page, and then just use my Gmail account to login.

Let’s see it in action

OK, if you’re really that excited about it.

Here’s an example url:

http://antelopecomments.appspot.com/get/blog.antelopelovefan.com

Click on that link and, as of right now, you’re going to see something like this

{"46540": {"comment": "This is a test comment", "pagename": "search-replace-with-vim", "sitename": "blog.antelopelovefan.com", "email": "tech@antelopelovefan.com", "author": "Mark Biek"}}

That’s a JSON string that shows a single comment (id 46540) attached to this site (blog.antelopelovefan.com) and the page search-replace-with-vim.

I could also do this to just get back the search-replace-with-vim page comments (although there aren’t any other pages right now so this url returns the same thing).

http://antelopecomments.appspot.com/get/blog.antelopelovefan.com/search-replace-with-vim

And then I can do this if I just want that one comment with id 46540

http://antelopecomments.appspot.com/get/blog.antelopelovefan.com/search-replace-with-vim/46540

I’m not doing anything with the above link yet but it’ll come in handy for permanent links to specific comments.

So how does it get used?

It’s funny because I think I wrote 3 times more PHP & Javascript code to make use of the comment engine than I wrote Python code for the back-end.

None of the PHP/JS stuff is very complicated.

  • I wrote a couple of classes which use cURL to do the appropriate GET & POST calls.
  • All of the JSON manipulation in PHP is handled via json_encode and json_decode.
  • The Javascript makes heavy use of Prototype and its Ajax library.
  • The form is protected using reCAPTCHA which is completely free and dropped right in using their PHP library.

Most of what’s remaining on the PHP side is reorganizing so I can easily attach comments to other PHP-based sites.

So, if all goes well, I should be to have comments available on this site soon.

Foray into the Google App Engine

I’ve been hearing a lot (good and bad) about the Google App Engine.

Aside from the fears of Skynet Google ruling the world, I find the idea of the App Engine really fascinating. To not have to worry about the normal scaling issues! To be able to wield the raw power of Google!

Of course it’s not like I really need that power for the scale I’m operating on so I guess the best reasons are

  • because it’s neat
  • because I need a Python hobby project

So I’ve decided to write a comment engine that uses the App Engine for the back end.

Here are my goals:

  • Be able to use it for comments across multiple sites
  • Be able to access it from any language that supports HTTP requests and JSON.
  • Be at least slightly difficult to spam.

That last one is going to be tricky.

My plan so far is that each site that uses the comment engine will get a secret key that it uses to send requests. That should (hopefully) prevent people from submitting comments all willy-nilly from a non-authorized site. The sites themselves will also need to have some mechanism at the comment-posting level to make it slightly harder for spammers.

And that’s only for posting. I’ve decided that it doesn’t matter retrieves comments.

At this point, I’m just focusing on putting comments in and getting comments back out. Some method for managing (ie deleting) comments and sites will come later.


Hello World!

Following the Getting Started guide got me a very simple ‘hello world’ app in about 5 minutes (running locally). Actually deploying the thing to Google was as easy as could be.

Friendly URLs

I’d figured out roughly how I wanted the various urls to work but I was having some trouble figuring out how to implement friendly urls. Some googling lead me to this:

application = webapp.WSGIApplication(
                                     [
                                       ( '/', MainPage),
                                       ( r'/get/(.*)/(.*)', HandleFoo)
                                     ], debug=True)

You saw in the Getting Started guide (which you read already, right?) how to set up your application as an WSGI application. The above is defining the application and the urls it handles. Each url is bound to a class.

In the case of the MainPage class, we’re handling the just root url ‘/’.

In the case of HandleFoo, we’re using a regular expression for the url. The neat part happens when we define the HandleFoo class.

class HandleFoo(webapp.RequestHandler);
    def get(self, foo, bar):
        self.response.out.write(foo)
        self.response.out.write(bar)

Remember our regular expression from before?

/get/(.*)/(.*)

This handles any url in the form /get/stuff/morestuff and hands that request off to the HandleFoo class (which is only handling GET requests, hence the get method).

Each item in the regular expression that’s surrounded by parentheses gets passed as a parameter to the get method of the class.

So, for the url /get/stuff/morestuff, the get method is going to output

'stuff'
'morestuff'

And there you have it. Friendly urls with the Google App Engine.

I’m off to figure out how the simplejson library works.