No description, website, or topics provided.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
battlenet
handlers
migrations
scripts
static
templates
.gitignore
License.txt
Readme.md
alembic.ini
bot.rb
fetch_servers.py
handler.py
metamodel.py
model.py
requirements.txt
serve.py
sms.py
wow_servers.py

Readme.md

Requirements

Install Python 2.7 and then run:

easy_install flask sqlalchemy coffeescript alembic twilio
easy_install --index-url https://code.stripe.com --upgrade stripe
git clone https://github.com/trentm/python-markdown2.git
cd python-markdown2
sudo python setup.py install

Or, install pip and then run:

pip install -r requirements.txt

Writing scripts

Scripts can be placed in the scripts/ directory. They can either be .js or .coffee. CoffeeScript source will be cached after compilation.

To reference from HTML, use scripts/foo.js no matter whether it's Javascript or CoffeeScript.

Routing and You

Example file, handlers/echo.py:

from handler import handler

@handler
def get_index(id, bar=None):
	return 'foo %r %r' % (id, bar)

This will create a route for /echo/<id> that takes an optional GET parameter called bar. Hitting /echo/blah?bar=baz will return: foo u'blah' u'baz'. Note the unicode strings.

Dear Flask, it's me, Cody

If you are modifying data, make sure you start your function name with post_ rather than get_. This enforces the POST method and will require a CSRF token.

How the route was won

Routes are generated based on handler module name and method name. The code for this is really straightforward:

if module == 'index':
	route = '/'
else:
	route = '/%s/' % module
if name != 'index':
	route += '%s/' % name
if len(args) and args[0] == 'id':
	route += '<id>'

So that means that a handler module named index.py is the very root of the web app. A method named index (GET or POST -- you can have both if it makes sense!) is the root of a given handler. So the application's handler for / is a method named get_index in a handler module named index.py. Got it? Good.

The id argument must be the first to the function if you want to have it. This is handy for URLs like /user/55. All non-id arguments are optional. Handle their non-existence or perish.

Template Magic

One additional way to use handlers is to automatically spit out JSON or put your data into a template.

@handler(json=True)
def get_foo():
	return True

This will return true as it's JSON-encoded.

@handler('login')
def get_login():
	return dict(status='Login failed')

This will automatically output your login template (templates/login.html) with the status variable assigned.

RPC

Handlers can also provide automatic RPC.

@handler
def rpc_foo(blah):
	return dict(foo='bar', arg=blah)

This will automatically generate an RPC stub, which can be called from CoffeeScript:

$rpc.ourhandlermodule.foo 'baz', (data) ->
	console.log data

This will print out a dict {foo: 'bar', arg: 'baz'}. RPC methods cannot take id (they're assumed to just be another parameter), always return JSON, and can't have a template applied to them, obviously.

Authorization

Handlers can take care of high-level authorization.

@handler(admin=True)
def get_admin():
    ...

@handler(authed=True)
def get_user(id):
    ...

Make sure that you handle fine-grained authorization in your own handlers.

CSRF

CSRF tokens are taken care of on RPC calls and are required for all POSTs. Inside your forms, place $CSRF$ at the beginning and it'll be dealt with.

Migrations

We're using Alembic for migrations, and they live in migrations/. Read this for more info.

Ensure you create a migration for anything that affects prod, but development should be done with SQLite and you should simply nuke your DB for each model change.