Browse files

adding a lookup counter

  • Loading branch information...
1 parent d5a3462 commit 3760cf7cb7c47f47bc929bd914900a41fd2f7cce @peterbe committed Oct 11, 2011
Showing with 172 additions and 64 deletions.
  1. +56 −62 handlers.py
  2. +3 −0 static/css/style.css
  3. +50 −0 static/js/lookups.js
  4. +1 −0 templates/base.html
  5. +1 −0 templates/home.html
  6. +47 −0 templates/lookups.html
  7. +1 −1 templates/test.html
  8. +13 −1 tests/test_handlers.py
View
118 handlers.py
@@ -64,6 +64,21 @@ def get(self):
@route('/jsonp', name='jsonp')
class FollowsHandler(BaseHandler, tornado.auth.TwitterMixin):
+ def increment_lookup_count(self, username, usernames, jsonp=False):
+ if jsonp:
+ key = 'lookups:jsonp'
+ else:
+ key = 'lookups:json'
+ if not isinstance(usernames, int):
+ usernames = len(usernames)
+ self.redis.incr(key)
+
+ key = 'lookups:username:%s' % username
+ self.redis.incr(key)
+
+ key = 'lookups:usernames'
+ self.redis.incr(key, usernames)
+
@tornado.web.asynchronous
@tornado.gen.engine
def get(self):
@@ -123,15 +138,15 @@ def get(self):
self.finish()
return
+ self.increment_lookup_count(this_username, len(usernames), jsonp=jsonp)
+
results = {}
# pick some up already from the cache
_drop = set()
for username in usernames:
key = 'follows:%s:%s' % (this_username, username)
value = self.redis.get(key)
if value is not None:
- #print repr(username)
- #print "\t", repr(value)
results[username] = bool(int(value))
_drop.add(username)
usernames -= _drop
@@ -213,6 +228,12 @@ def get_next_url(self):
@route('/auth/twitter/', name='auth_twitter')
class TwitterAuthHandler(BaseAuthHandler, tornado.auth.TwitterMixin):
+ def increment_authentication_count(self, username):
+ key = 'auths:username:%s' % username
+ self.redis.incr(key)
+ key = 'auths:total'
+ self.redis.incr(key)
+
@tornado.web.asynchronous
def get(self):
if self.get_argument("oauth_token", None):
@@ -236,6 +257,8 @@ def _on_auth(self, user_struct):
user['access_token'] = access_token
user.save()
+ self.increment_authentication_count(username)
+
self.set_secure_cookie("user",
str(user['_id']),
expires_days=30, path='/')
@@ -401,72 +424,14 @@ def get(self):
@route('/everyone', name='everyone')
class EveryoneIFollowHandler(BaseHandler, tornado.auth.TwitterMixin):
- @tornado.web.asynchronous
- @tornado.gen.engine
+ #@tornado.web.asynchronous
+ #@tornado.gen.engine
def get(self):
-
current_user = self.get_current_user()
if not current_user:
self.redirect(self.reverse_url('auth_twitter'))
return
-
-# this_username = current_user['username']
-# access_token = current_user['access_token']
-# key = 'friends:%s' % this_username
-# result = self.redis.get(key)
-# if result is None:
-# result = yield tornado.gen.Task(self.twitter_request,
-# "/friends/ids",
-# screen_name=this_username,
-# access_token=access_token
-# )
-# self.redis.setex(key, json_encode(result), 60 * 60)
-# else:
-# result = json_decode(result)
-# # now turn these IDs into real screen names
-# unknown = []
-# screen_names = []
-# for id_ in result:
-# user = self.db.User.find_one({'user_id': id_})
-# if user:
-# screen_names.append(user['username'])
-# else:
-# key = 'screen_name:%s' % id_
-# screen_name = self.redis.get(key)
-# if screen_name is None:
-# unknown.append(id_)
-# else:
-# screen_names.append(screen_name)
-#
-# buckets = utils.bucketize(unknown, 100)
-#
-# for bucket in buckets:
-# users = None
-# attempts = 0
-# while True:
-# users = yield tornado.gen.Task(self.twitter_request,
-# "/users/lookup",
-# user_id=','.join(str(x) for x in bucket)
-# )
-# if users is not None:
-# break
-# else:
-# from time import sleep
-# sleep(1)
-# attempts += 1
-# if attempts > 3:
-# raise HTTPError(500, "Unable to connect to twitter")
-# for user in users:
-# username = user['screen_name']
-# key = 'screen_name:%s' % user['id']
-# self.redis.setex(key, username, 7 * 24 * 60 * 60)
-# screen_names.append(username)
-#
-# assert len(result) == len(screen_names)
-#
-# screen_names.sort()
options = {}
-# options['screen_names'] = screen_names
options['page_title'] = "Everyone I follow"
self.render('everyone.html', **options)
@@ -538,3 +503,32 @@ def get(self):
screen_names.sort()
self.write_json(screen_names)
self.finish()
+
+
+@route('/lookups', name='lookups')
+class LookupsHandler(BaseHandler):
+
+ def get_lookups(self, username=None):
+ data = {}
+ data['lookups_json'] = self.redis.get('lookups:json') or 0
+ data['lookups_jsonp'] = self.redis.get('lookups:jsonp') or 0
+ data['auths'] = self.redis.get('auths:total') or 0
+ data['lookups_usernames'] = self.redis.get('lookups:usernames') or 0
+ if username:
+ print "NotImplmented"
+ for key, value in data.items():
+ data[key] = int(value)
+ return data
+
+ def get(self):
+ options = {}
+ options['page_title'] = "Lookups"
+ options.update(self.get_lookups())
+ self.render('lookups.html', **options)
+
+@route('/lookups.json', name='lookups_json')
+class LookupsJSONHandler(LookupsHandler):
+
+ def get(self):
+ data = self.get_lookups()
+ self.write_json(data)
View
3 static/css/style.css
@@ -116,3 +116,6 @@ img.screengrab1 {float:left; margin-top: 20px; opacity:0.7;}
img.screengrab {float: left; margin-right: 10px;}
h3.confused {font-size:35px;}
span.grey {color:#c1c1c1;}
+
+header h1 { }
+header p#home-link { font-size:0.8em; margin-top:0; }
View
50 static/js/lookups.js
@@ -0,0 +1,50 @@
+
+function compareAssociativeArrays(a, b) {
+ function nrKeys(a) {
+ var i = 0;
+ for (key in a) {
+ i++;
+ }
+ return i;
+ }
+ if (a == b) {
+ return true;
+ }
+ if (nrKeys(a) != nrKeys(b)) {
+ return false;
+ }
+ for (key in a) {
+ if (a[key] != b[key]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+var previous = {}, incr = 0; // global
+function update() {
+ $.getJSON(JSON_URL, function(response) {
+ $('#lookups-total').text(response.lookups_json + response.lookups_jsonp);
+ $('#lookups-json').text(response.lookups_json);
+ $('#lookups-jsonp').text(response.lookups_jsonp);
+ $('#lookups-usernames').text(response.lookups_usernames);
+ $('#auths').text(response.auths);
+ var change = !compareAssociativeArrays(response, previous);
+ previous = response;
+
+ var t;
+ if (change) {
+ t = 1;
+ incr = 0;
+ } else {
+ t = Math.min(3 + incr, 10);
+ incr += 0.1;
+ }
+ console.log(Math.ceil(t*1000));
+ setTimeout(update, Math.ceil(t * 1000));
+ });
+}
+$(function() {
+ setTimeout(update, 5 * 1000);
+});
View
1 templates/base.html
@@ -13,6 +13,7 @@
<header>
<h1><a href="/">Too Cool For Me<span class="q">?</span></a></h1>
+ {% block home_link %}<p id="home-link"><a href="/">&larr; home</a></p>{% end %}
{% block extra_header %}
{% end %}
</header>
View
1 templates/home.html
@@ -1,5 +1,6 @@
{% extends "base.html" %}
+{% block home_link %}{% end %}
{% block extra_header %}
<h3>Find out who on <a href="https://twitter.com/">Twitter</a> follows you back <span class="grey">(and who is just too cool for you)</span></h3>
{% end %}
View
47 templates/lookups.html
@@ -0,0 +1,47 @@
+{% extends "base.html" %}
+
+{% block extra_head %}
+<style>
+th, td { background-color:#efefef; padding:12px 27px; }
+th { text-align:left; }
+td { font-size:2.5em; font-weight:bold; }
+</style>
+{% end %}
+
+
+{% block content %}
+<h1>Lookups</h1>
+
+<p>In other words, is this app being actively used?</p>
+
+<table>
+ <tr>
+ <th>Total number of usernames looked up:</th>
+ <td id="lookups-usernames">{{ lookups_usernames }}</td>
+ </tr>
+ <tr>
+ <th>Twitter requests total:</th>
+ <td id="lookups-total">{{ lookups_json + lookups_jsonp }}</td>
+ </tr>
+ <tr>
+ <th>Twitter requests by JSON:</th>
+ <td id="lookups-json">{{ lookups_json }}</td>
+ </tr>
+ <tr>
+ <th>Twitter requests by JSONP:</th>
+ <td id="lookups-jsonp">{{ lookups_jsonp }}</td>
+ </tr>
+ <tr>
+ <th>Authentications:</th>
+ <td id="auths">{{ auths }}</td>
+ </tr>
+</table>
+{% end %}
+
+{% block extra_js %}
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
+<script>
+var JSON_URL = '{{ reverse_url('lookups_json') }}';
+</script>
+<script src="{{ static_url('js/lookups.js') }}"></script>
+{% end %}
View
2 templates/test.html
@@ -6,7 +6,7 @@
<p>Type some Twitter user names below to see who's too cool for you.<br>
Also include some user names you know follow you:</p>
<div style="float:left">
-<textarea name="usernames" cols="20" rows="20">ConanOBrien
+<textarea name="usernames" cols="20" rows="20">katyperry
justinbieber
</textarea><input type="submit" value="Test">
</div>
View
14 tests/test_handlers.py
@@ -40,6 +40,9 @@ def test_twitter_login(self):
self.assertEqual(response.code, 200)
self.assertTrue('Login with Twitter' in response.body)
+ self.assertEqual(int(self.redis.get('auths:total')), 1)
+ self.assertEqual(int(self.redis.get('auths:username:peterbe')), 1)
+
def test_twitter_login_twitter_failing(self):
TwitterAuthHandler.get_authenticated_user = \
make_twitter_get_authenticated_user_callback(None)
@@ -98,6 +101,7 @@ def test_test_service(self):
def test_json(self):
+ self.assertEqual(self.redis.get('lookups:json'), None)
FollowsHandler.twitter_request = \
make_mock_twitter_request({u'relationship': {
u'target': {u'followed_by': False,
@@ -132,6 +136,10 @@ def test_json(self):
struct = json.loads(response.body)
self.assertEqual(struct['obama'], False)
+ self.assertEqual(int(self.redis.get('lookups:json')), 2)
+ self.assertEqual(int(self.redis.get('lookups:username:peterbe')), 2)
+ self.assertEqual(int(self.redis.get('lookups:usernames')), 2)
+
def test_json_with_overriding_you(self):
FollowsHandler.twitter_request = \
make_mock_twitter_request({u'relationship': {
@@ -192,6 +200,11 @@ def test_jsonp(self):
self.assertEqual(response.code, 200)
self.assertEqual(response.body, 'FOO({"obama": false})')
+ self.assertEqual(int(self.redis.get('lookups:json')), 0)
+ self.assertEqual(int(self.redis.get('lookups:jsonp')), 2)
+ self.assertEqual(int(self.redis.get('lookups:username:peterbe')), 2)
+ self.assertEqual(int(self.redis.get('lookups:usernames')), 2)
+
def test_jsonp(self):
url = self.reverse_url('jsonp')
response = self.client.get(url, {'username': 'obama'})
@@ -201,7 +214,6 @@ def test_jsonp(self):
self.assertEqual(response.code, 200)
self.assertTrue(response.body.startswith('FOO({"ERROR":'))
-
def test_following_none_cached(self):
FollowsHandler.twitter_request = \
make_mock_twitter_request([

0 comments on commit 3760cf7

Please sign in to comment.