]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Add a simple end-to-end demo of TwitterMixin.
authorBen Darnell <ben@bendarnell.com>
Sat, 1 Jun 2013 01:46:53 +0000 (21:46 -0400)
committerBen Darnell <ben@bendarnell.com>
Sat, 1 Jun 2013 01:46:53 +0000 (21:46 -0400)
.gitignore
demos/twitter/home.html [new file with mode: 0644]
demos/twitter/twitterdemo.py [new file with mode: 0644]
tornado/auth.py

index c84e747f4341e8b3e111c19299d8a77fe3b7dada..af3cc1bccca461282faff257c4a1ae3eeaf9b5be 100644 (file)
@@ -13,3 +13,5 @@ _auto2to3*
 /.coverage
 /htmlcov/
 /env/
+# Used in demo apps
+secrets.cfg
diff --git a/demos/twitter/home.html b/demos/twitter/home.html
new file mode 100644 (file)
index 0000000..a2c159c
--- /dev/null
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <title>Tornado Twitter Demo</title>
+  </head>
+  <body>
+    <ul>
+      {% for tweet in timeline %}
+      <li><b>{{ tweet['user']['screen_name'] }}</b>: {{ tweet['text'] }}</li>
+      {% end %}
+    </ul>
+  </body>
+</html>
diff --git a/demos/twitter/twitterdemo.py b/demos/twitter/twitterdemo.py
new file mode 100644 (file)
index 0000000..3cc23f9
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+"""A simplistic Twitter viewer to demonstrate the use of TwitterMixin.
+
+To run this app, you must first register an application with Twitter:
+  1) Go to https://dev.twitter.com/apps and create an application.
+     Your application must have a callback URL registered with Twitter.
+     It doesn't matter what it is, but it has to be there (Twitter won't
+     let you use localhost in a registered callback URL, but that won't stop
+     you from running this demo on localhost).
+  2) Create a file called "secrets.cfg" and put your consumer key and
+     secret (which Twitter gives you when you register an app) in it:
+       twitter_consumer_key = 'asdf1234'
+       twitter_consumer_secret = 'qwer5678'
+     (you could also generate a random value for "cookie_secret" and put it
+     in the same file, although it's not necessary to run this demo)
+  3) Run this program and go to http://localhost:8888 (by default) in your
+     browser.
+"""
+
+import logging
+
+from tornado.auth import TwitterMixin
+from tornado.escape import json_decode, json_encode
+from tornado.ioloop import IOLoop
+from tornado import gen
+from tornado.options import define, options, parse_command_line, parse_config_file
+from tornado.web import Application, RequestHandler, authenticated
+
+define('port', default=8888, help="port to listen on")
+define('config_file', default='secrets.cfg',
+       help='filename for additional configuration')
+
+define('debug', default=False, group='application',
+       help="run in debug mode (with automatic reloading)")
+# The following settings should probably be defined in secrets.cfg
+define('twitter_consumer_key', type=str, group='application')
+define('twitter_consumer_secret', type=str, group='application')
+define('cookie_secret', type=str, group='application',
+       default='__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE__',
+       help="signing key for secure cookies")
+
+class BaseHandler(RequestHandler):
+    COOKIE_NAME = 'twitterdemo_user'
+
+    def get_current_user(self):
+        user_json = self.get_secure_cookie(self.COOKIE_NAME)
+        if not user_json:
+            return None
+        return json_decode(user_json)
+
+class MainHandler(BaseHandler, TwitterMixin):
+    @authenticated
+    @gen.coroutine
+    def get(self):
+        timeline = yield self.twitter_request(
+            '/statuses/home_timeline',
+            access_token=self.current_user['access_token'])
+        self.render('home.html', timeline=timeline)
+
+class LoginHandler(BaseHandler, TwitterMixin):
+    @gen.coroutine
+    def get(self):
+        if self.get_argument('oauth_token', None):
+            user = yield self.get_authenticated_user()
+            self.set_secure_cookie(self.COOKIE_NAME, json_encode(user))
+            self.redirect(self.get_argument('next', '/'))
+        else:
+            yield self.authorize_redirect(callback_uri=self.request.full_url())
+
+class LogoutHandler(BaseHandler):
+    def get(self):
+        self.clear_cookie(self.COOKIE_NAME)
+
+def main():
+    parse_command_line(final=False)
+    parse_config_file(options.config_file)
+
+    app = Application(
+        [
+            ('/', MainHandler),
+            ('/login', LoginHandler),
+            ('/logout', LogoutHandler),
+        ],
+        login_url='/login',
+        **options.group_dict('application'))
+    app.listen(options.port)
+
+    logging.info('Listening on http://localhost:%d' % options.port)
+    IOLoop.instance().start()
+
+if __name__ == '__main__':
+    main()
index 8e1668edb5ae677979b7f80eee40bf7011af0169..d210d862cccd4f94e6aa7d4092cc0f5a16bd295e 100644 (file)
@@ -409,7 +409,7 @@ class OAuthMixin(object):
     def _on_request_token(self, authorize_url, callback_uri, callback,
                           response):
         if response.error:
-            raise Exception("Could not get request token")
+            raise Exception("Could not get request token: %s" % response.error)
         request_token = _oauth_parse_response(response.body)
         data = (base64.b64encode(escape.utf8(request_token["key"])) + b"|" +
                 base64.b64encode(escape.utf8(request_token["secret"])))