Skip to content
This repository has been archived by the owner on Mar 16, 2020. It is now read-only.

Commit

Permalink
using mongodb now
Browse files Browse the repository at this point in the history
  • Loading branch information
peterbe committed Sep 25, 2011
1 parent 1159e8f commit 8775fee
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 74 deletions.
4 changes: 4 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ def __init__(self, database_name=None):
self.redis = redis.client.Redis(settings.REDIS_HOST,
settings.REDIS_PORT)

from models import connection
self.db = connection[settings.DATABASE_NAME]



def main(): # pragma: no cover
tornado.options.parse_command_line()
Expand Down
1 change: 1 addition & 0 deletions bin/_run_coverage_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
COVERAGE_MODULES = [
'app',
'handlers',
'models',
]

def all():
Expand Down
32 changes: 32 additions & 0 deletions bin/redis2mongo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env python
import os
import site

ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
path = lambda *a: os.path.join(ROOT,*a)

site.addsitedir(path('.'))
site.addsitedir(path('vendor'))

import redis as redis_

def run():
import settings
from models import connection
db = connection[settings.DATABASE_NAME]
redis = redis_.client.Redis(settings.REDIS_HOST,
settings.REDIS_PORT)

for username in redis.smembers('allusernames'):
key = 'access_tokens:%s' % username
access_token = redis.get(key)
if access_token:
user = db.User.find_one({'username': username})
if not user:
user = db.User()
user['username'] = username
user['access_token'] = access_token
user.save()

if __name__ == '__main__':
run()
2 changes: 2 additions & 0 deletions bin/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
python bin/_run_tests.py --logging=error $@
94 changes: 44 additions & 50 deletions handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
from tornado_utils.routes import route
#from tornado_utils.decorators import login_required
from tornado.escape import json_decode, json_encode
from pymongo.objectid import InvalidId, ObjectId
#import settings

from models import User


class BaseHandler(tornado.web.RequestHandler):

Expand All @@ -20,14 +23,21 @@ def write_jsonp(self, callback, struct):
self.write('%s(%s)' % (callback, tornado.escape.json_encode(struct)))

def get_current_user(self):
username = self.get_secure_cookie('user')
if username:
return unicode(username, 'utf8')
_id = self.get_secure_cookie('user')
if _id:
try:
return self.db.User.find_one({'_id': ObjectId(_id)})
except InvalidId: # pragma: no cover
return self.db.User.find_one({'username': _id})

@property
def redis(self):
return self.application.redis

@property
def db(self):
return self.application.db


@route('/')
class HomeHandler(BaseHandler):
Expand All @@ -37,11 +47,6 @@ def get(self):
'page_title': 'Too Cool for Me?',
}
user = self.get_current_user()
if user:
# check that we still have the access token
key = 'access_tokens:%s' % user
if not self.redis.get(key):
user = None
if user:
url = '/static/bookmarklet.js'
url = '%s://%s%s' % (self.request.protocol,
Expand Down Expand Up @@ -96,23 +101,18 @@ def get(self):

# All of this is commented out until I can figure out why cookie
# headers aren't sent from bookmarklet's AJAX code
this_username = self.get_argument('you', self.get_current_user())
# this_username = self.get_current_user()
# #print "THIS_USERNAME", repr(this_username)
# you = self.get_argument('you', None) # optional
# #print "YOU", repr(you)
# if you:
# print "THIS_USERNAME", repr(this_username)
# if this_username != you:
# self.write_json({
# 'ERROR': "Logged in on %s as '%s'" % this_username
# })
# return
# if you in usernames:
# usernames.remove(you)
access_token = self.redis.get('access_tokens:%s' % this_username)
if access_token:
access_token = json_decode(access_token)
this_username = self.get_argument('you', None)
access_token = None
if this_username is not None:
user = self.db.User.find_one({'username': this_username})
if user:
access_token = user['access_token']
else:
user = self.get_current_user()
if user:
this_username = user['username']
access_token = user['access_token']

if not access_token:
msg = {'ERROR': ('Not authorized. Go to http://%s and sign in' %
self.request.host)}
Expand All @@ -122,9 +122,6 @@ def get(self):
self.write_json(msg)
self.finish()
return
#print "USERNAMES"
#pprint(usernames)
#print

results = {}
# pick some up already from the cache
Expand Down Expand Up @@ -232,12 +229,18 @@ def _on_auth(self, user_struct):
self.render('twitter_auth_failed.html', **options)
return
username = user_struct.get('username')
self.redis.rpush('usernames', username)
#self.redis.rpush('usernames', username)
access_token = user_struct['access_token']
assert access_token
self.redis.set('access_tokens:%s' % username, json_encode(access_token))
user = self.db.User.find_one({'username': username})
if user is None:
user = self.db.User()
user['username'] = username
user['access_token'] = access_token
user.save()

self.set_secure_cookie("user",
username.encode('utf8'),
str(user['_id']),
expires_days=30, path='/')
self.redirect('/')

Expand Down Expand Up @@ -275,22 +278,19 @@ class FollowingHandler(BaseHandler, tornado.auth.TwitterMixin):
@tornado.web.asynchronous
def get(self, username):
options = {'username': username}
this_username = self.get_current_user()
if not this_username:
#this_username = self.get_current_user()
current_user = self.get_current_user()
if not current_user:
self.redirect(self.reverse_url('auth_twitter'))
return
this_username = current_user['username']
options['this_username'] = this_username
options['follows'] = None
key = 'follows:%s:%s' % (this_username, username)
value = self.redis.get(key)
if value is None:
access_token = self.redis.get('access_tokens:%s' % this_username)
if not access_token:
self.write('ERROR: Not authorized with Twitter for %s' %
self.request.host)
self.finish()
return
access_token = json_decode(access_token)
#access_token = self.redis.get('access_tokens:%s' % this_username)
access_token = current_user['access_token']
self.twitter_request(
"/friendships/show",
source_screen_name=this_username,
Expand All @@ -302,8 +302,6 @@ def get(self, username):
)
else:
self._on_friendship(bool(int(value)), None, options)
#options['follows'] = bool(int(value))
#self._fetch_info(options)

def _on_friendship(self, result, key, options):
if result is None:
Expand All @@ -326,13 +324,13 @@ def _on_friendship(self, result, key, options):
def _fetch_info(self, options, username=None):
if username is None:
username = options['username']

key = 'info:%s' % username
value = self.redis.get(key)

if value is None:
access_token = self.redis.get('access_tokens:%s' %
options['this_username'])
access_token = json_decode(access_token)
user = self.db.User.find_one({'username': options['this_username']})
access_token = user['access_token']
self.twitter_request(
"/users/show",
screen_name=username,
Expand All @@ -343,10 +341,6 @@ def _fetch_info(self, options, username=None):
)
else:
self._on_info(json_decode(value), None, options, username)
#value = json_decode(value)
#options['info'] = value
#pprint(value)
#self._render(options)

def _on_info(self, result, key, options, username):
if result is None:
Expand Down Expand Up @@ -395,7 +389,7 @@ def _set_ratio(self, options, key):


@route(r'/coolest', name='coolest')
class CoolestHandler(BaseHandler):
class CoolestHandler(BaseHandler): # pragma: no cover (under development)

def get(self):
options = {}
Expand Down
19 changes: 19 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import datetime
from mongolite import Connection, Document
connection = Connection()

@connection.register
class User(Document):
__collection__ = 'users'
structure = {
'username': unicode,
'access_token': dict,
'modify_date': datetime.datetime
}

default_values = {'modify_date':datetime.datetime.utcnow}

def save(self, *args, **kwargs):
if '_id' in self and kwargs.get('update_modify_date', True):
self.modify_date = datetime.datetime.utcnow()
super(User, self).save(*args, **kwargs)
2 changes: 2 additions & 0 deletions settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
REDIS_HOST = 'localhost'
REDIS_PORT = 6379

DATABASE_NAME = 'toocool'

try:
from local_settings import *
except ImportError:
Expand Down
4 changes: 2 additions & 2 deletions templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ <h3>Find out who on <a href="https://twitter.com/">Twitter</a> follows you back
<!-- LOGGED IN BLOCK -->
<p class="login">
<span class="tick twitter-login">&#x2713;</span>
logged in as <strong>@{{ user }}</strong>
logged in as <strong>@{{ user['username'] }}</strong>
<span style="font-size:0.7em">(<a href="/auth/logout/">Log out</a>)</span>
<br/>
<a href="/test">Test the service manually</a>
Expand Down Expand Up @@ -39,7 +39,7 @@ <h3>Find out who on <a href="https://twitter.com/">Twitter</a> follows you back
<p><span class="title">1. Add the bookmarklet</span>
<span class="explain"><strong>Drag-and-drop</strong> this link (bookmarklet) ...</span>
<a class="bookmarklet" href="javascript:void((function(){var%20e=document.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('src','{{ full_bookmarklet_url }}');document.body.appendChild(e)})())" onclick="return false">
<img src="/static/images/twitter-small-mirrored.png" alt="twitter bird">
<img src="/static/images/twitter-small-mirrored.png" alt="">
<span class="text">Too cool for me?</span></a>
</p>
<p style="clear:left">
Expand Down
19 changes: 11 additions & 8 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ class _DatabaseTestCaseMixin(object):
def setup_connection(self):
if not self._once:
self._once = True
#self.db =
self._emptyCollections()

def teardown_connection(self):
# do this every time
pass
#self._emptyCollections()
self._emptyCollections()

def _emptyCollections(self):
pass

[self.db.drop_collection(x) for x
in self.db.collection_names()
if x not in ('system.indexes',)]


class BaseAsyncTestCase(AsyncHTTPTestCase, _DatabaseTestCaseMixin):
Expand All @@ -55,15 +54,19 @@ def setUp(self):

def tearDown(self):
super(BaseHTTPTestCase, self).tearDown()
self.db.flushall()
self.redis.flushall()

def get_app(self):
return app.Application(database_name='test')

@property
def db(self):
def redis(self):
return self.get_app().redis

@property
def db(self):
return self.get_app().db

def decode_cookie_value(self, key, cookie_value):
try:
return re.findall('%s=([\w=\|]+);' % key, cookie_value)[0]
Expand Down
Loading

0 comments on commit 8775fee

Please sign in to comment.