examples/tornado/example.py
#!/usr/bin/env python
#
# Copyright 2010 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""A barebones Tornado application that uses Facebook for login.
Assumes a database with a schema as specified in schema.sql. We store a
local copy of basic user data so we don't need to make a round-trip to
the Facebook API on every request once a user has logged in.
"""
import facebook
import tornado.database
import tornado.httpserver
import tornado.options
import tornado.web
from tornado.options import define, options
define("port", default=8888, help="run on the given port", type=int)
define("facebook_app_id", help="Facebook Application ID")
define("facebook_app_secret", help="Facebook Application Secret")
define("mysql_host", help="MySQL database host")
define("mysql_database", help="MySQL database database")
define("mysql_user", help="MySQL database user")
define("mysql_password", help="MySQL database password")
class BaseHandler(tornado.web.RequestHandler):
"""Implements authentication via the Facebook JavaScript SDK cookie."""
def get_current_user(self):
cookies = dict((n, self.cookies[n].value) for n in self.cookies.keys())
cookie = facebook.get_user_from_cookie(
cookies, options.facebook_app_id, options.facebook_app_secret
)
if not cookie:
return None
user = self.db.get("SELECT * FROM users WHERE id = %s", cookie["uid"])
if not user:
# TODO: Make this fetch async rather than blocking
graph = facebook.GraphAPI(cookie["access_token"])
profile = graph.get_object("me")
self.db.execute(
"REPLACE INTO users (id, name, profile_url, access_token) "
"VALUES (%s,%s,%s,%s)",
profile["id"],
profile["name"],
profile["link"],
cookie["access_token"],
)
user = self.db.get(
"SELECT * FROM users WHERE id = %s", profile["id"]
)
elif user.access_token != cookie["access_token"]:
self.db.execute(
"UPDATE users SET access_token = %s WHERE id = %s",
cookie["access_token"],
user.id,
)
return user
@property
def db(self):
if not hasattr(BaseHandler, "_db"):
BaseHandler._db = tornado.database.Connection(
host=options.mysql_host,
database=options.mysql_database,
user=options.mysql_user,
password=options.mysql_password,
)
return BaseHandler._db
class MainHandler(BaseHandler):
def get(self):
self.render("example.html", options=options)
def main():
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(
tornado.web.Application([(r"/", MainHandler)])
)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()