Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 298 lines (260 sloc) 10.436 kb
6441c6d0 »
2011-08-22 initial commit
1 from pprint import pprint
2 import tornado.auth
3 import tornado.web
4 from tornado.web import HTTPError
5 from utils.routes import route
362d15e0 »
2011-08-26 a basic website to go with it
6 from utils.decorators import login_required
6441c6d0 »
2011-08-22 initial commit
7 from tornado.escape import json_decode, json_encode
8 import settings
9
10 class BaseHandler(tornado.web.RequestHandler):
11
12 def write_json(self, struct, javascript=False):
f0a8efdc »
2011-08-29 changing to a bookmarklet
13 self.set_header("Content-Type", "application/json; charset=UTF-8")
6441c6d0 »
2011-08-22 initial commit
14 self.write(tornado.escape.json_encode(struct))
15
16 def write_jsonp(self, callback, struct):
17 self.set_header("Content-Type", "text/javascript; charset=UTF-8")
18 self.write('%s(%s)' % (callback, tornado.escape.json_encode(struct)))
19
20 def get_current_user(self):
439d8ddb »
2011-08-25 working version
21 username = self.get_secure_cookie('user')
22 if username:
23 return unicode(username, 'utf8')
6441c6d0 »
2011-08-22 initial commit
24
25 @property
26 def redis(self):
27 return self.application.redis
28
29
439d8ddb »
2011-08-25 working version
30 @route('/')
31 class HomeHandler(BaseHandler):
32
33 def get(self):
34 options = {}
35 user = self.get_current_user()
36 if user:
37 url = '/static/bookmarklet.js'
38 url = '%s://%s%s' % (self.request.protocol,
39 self.request.host,
40 url)
41 options['full_bookmarklet_url'] = url
42
43 options['user'] = user
44 self.render('home.html', **options)
45
46
f0a8efdc »
2011-08-29 changing to a bookmarklet
47 @route('/json(p)?')
6441c6d0 »
2011-08-22 initial commit
48 class FollowsHandler(BaseHandler, tornado.auth.TwitterMixin):
49
50 @tornado.web.asynchronous
f0a8efdc »
2011-08-29 changing to a bookmarklet
51 def get(self, jsonp=False):
6441c6d0 »
2011-08-22 initial commit
52 if (self.get_argument('username', None) and
53 not self.get_argument('usernames', None)):
54 usernames = self.get_arguments('username')
55 else:
56 usernames = self.get_arguments('usernames')
57 if isinstance(usernames, basestring):
58 usernames = [usernames]
439d8ddb »
2011-08-25 working version
59 elif (isinstance(usernames, list)
60 and len(usernames) == 1
61 and ',' in usernames[0]):
62 usernames = [x.strip() for x in
63 usernames[0].split(',')
64 if x.strip()]
65 # make sure it's a unique list
66 usernames = set(usernames)
f0a8efdc »
2011-08-29 changing to a bookmarklet
67 if jsonp:
68 self.jsonp = self.get_argument('callback', 'callback')
69 else:
70 self.jsonp = False
71
72 # All of this is commented out until I can figure out why cookie
73 # headers aren't sent from bookmarklet's AJAX code
74 this_username = self.get_argument('you', self.get_current_user())
75 # this_username = self.get_current_user()
76 # #print "THIS_USERNAME", repr(this_username)
77 # you = self.get_argument('you', None) # optional
78 # #print "YOU", repr(you)
79 # if you:
80 # print "THIS_USERNAME", repr(this_username)
81 # if this_username != you:
82 # self.write_json({
83 # 'ERROR': "Logged in on %s as '%s'" % this_username
84 # })
85 # return
86 # if you in usernames:
87 # usernames.remove(you)
6441c6d0 »
2011-08-22 initial commit
88 access_token = self.redis.get('username:%s' % this_username)
89 if access_token:
90 access_token = json_decode(access_token)
439d8ddb »
2011-08-25 working version
91 if not access_token:
92 self.write_json({
93 'ERROR': ('Not authorized with Twitter for %s' %
94 self.request.host)
95 })
96 return
362d15e0 »
2011-08-26 a basic website to go with it
97 print "USERNAMES"
98 pprint(usernames)
439d8ddb »
2011-08-25 working version
99 #print
100
101 results = {}
102 # pick some up already from the cache
103 _drop = set()
104 for username in usernames:
105 key = 'follows:%s:%s' % (this_username, username)
106 value = self.redis.get(key)
107 if value is not None:
108 #print repr(username)
109 #print "\t", repr(value)
110 results[username] = bool(int(value))
111 _drop.add(username)
112 usernames -= _drop
6441c6d0 »
2011-08-22 initial commit
113
114 if len(usernames) == 1:
362d15e0 »
2011-08-26 a basic website to go with it
115 username = list(usernames)[0]
6441c6d0 »
2011-08-22 initial commit
116 # See https://dev.twitter.com/docs/api/1/get/friendships/show
117 self.twitter_request(
118 "/friendships/show",
119 source_screen_name=this_username,
120 target_screen_name=username,
121 access_token=access_token,
122 callback=self.async_callback(
439d8ddb »
2011-08-25 working version
123 lambda x: self._on_show(x, this_username, username, results)
6441c6d0 »
2011-08-22 initial commit
124 ),
125 )
439d8ddb »
2011-08-25 working version
126 elif usernames:
362d15e0 »
2011-08-26 a basic website to go with it
127 print "ACCESS_TOKEN"
128 print access_token
6441c6d0 »
2011-08-22 initial commit
129 # See https://dev.twitter.com/docs/api/1/get/friendships/lookup
130 self.twitter_request(
131 "/friendships/lookup",
132 screen_name=','.join(usernames),
133 access_token=access_token,
134 callback=self.async_callback(
439d8ddb »
2011-08-25 working version
135 lambda x: self._on_lookup(x, this_username, results)
6441c6d0 »
2011-08-22 initial commit
136 ),
137 )
439d8ddb »
2011-08-25 working version
138 else:
139 # all usernames were lookup'able by cache
f0a8efdc »
2011-08-29 changing to a bookmarklet
140 if self.jsonp:
141 self.write_jsonp(self.jsonp, results)
142 else:
143 self.write_json(results)
144 print "RETURNING"
145 pprint(results)
439d8ddb »
2011-08-25 working version
146 self.finish()
6441c6d0 »
2011-08-22 initial commit
147
439d8ddb »
2011-08-25 working version
148
149 def _on_lookup(self, result, this_username, data):
362d15e0 »
2011-08-26 a basic website to go with it
150 print "RESULT"
151 pprint(result)
6441c6d0 »
2011-08-22 initial commit
152 for each in result:
153 if 'followed_by' in each['connections']:
154 data[each['screen_name']] = True
155 else:
156 data[each['screen_name']] = False
439d8ddb »
2011-08-25 working version
157 key = 'follows:%s:%s' % (this_username, each['screen_name'])
158 self.redis.setex(key, int(data[each['screen_name']]), 60)
159
f0a8efdc »
2011-08-29 changing to a bookmarklet
160 if self.jsonp:
161 self.write_jsonp(self.jsonp, data)
162 else:
163 self.write_json(data)
164 print "RETURNING"
165 pprint(data)
6441c6d0 »
2011-08-22 initial commit
166 self.finish()
167
362d15e0 »
2011-08-26 a basic website to go with it
168 def _on_show(self, result, this_username, username, data):
6441c6d0 »
2011-08-22 initial commit
169 #print "RESULT"
170 #pprint(result)
171 target_follows = None
172 if result and 'relationship' in result:
173 target_follows = result['relationship']['target']['following']
439d8ddb »
2011-08-25 working version
174 key = 'follows:%s:%s' % (this_username, username)
175 self.redis.setex(key, int(bool(target_follows)), 60)
362d15e0 »
2011-08-26 a basic website to go with it
176 data[username] = target_follows
f0a8efdc »
2011-08-29 changing to a bookmarklet
177 if self.jsonp:
178 self.write_jsonp(self.jsonp, data)
179 else:
180 self.write_json(data)
181 print "RETURNING"
182 pprint(data)
6441c6d0 »
2011-08-22 initial commit
183 self.finish()
184
185
186 class BaseAuthHandler(BaseHandler):
187
188 def get_next_url(self):
189 return '/'
190
191 @route('/auth/twitter/', name='auth_twitter')
192 class TwitterAuthHandler(BaseAuthHandler, tornado.auth.TwitterMixin):
193
194 @tornado.web.asynchronous
195 def get(self):
196 if self.get_argument("oauth_token", None):
197 self.get_authenticated_user(self.async_callback(self._on_auth))
198 return
199 self.authenticate_redirect()
200
201 def _on_auth(self, user_struct):
202 if not user_struct:
203 raise HTTPError(500, "Twitter auth failed")
204 username = user_struct.get('username')
f0a8efdc »
2011-08-29 changing to a bookmarklet
205 self.redis.rpush('usernames', username)
6441c6d0 »
2011-08-22 initial commit
206 #first_name = user_struct.get('first_name', user_struct.get('name'))
207 #last_name = user_struct.get('last_name')
208 #email = user_struct.get('email')
209 access_token = user_struct['access_token']
210 self.redis.set('username:%s' % username, json_encode(access_token))
211 #profile_image_url = user_struct.get('profile_image_url', None)
f0a8efdc »
2011-08-29 changing to a bookmarklet
212 self.set_secure_cookie("user", username.encode('utf8'), expires_days=30, path='/')
6441c6d0 »
2011-08-22 initial commit
213 self.redirect('/')
214
215 @route(r'/auth/logout/', name='logout')
216 class AuthLogoutHandler(BaseAuthHandler):
217 def get(self):
218 self.clear_all_cookies()
219 self.redirect(self.get_next_url())
362d15e0 »
2011-08-26 a basic website to go with it
220
221
222 @route(r'/test', name='test')
223 class TestServiceHandler(BaseHandler):
224
225 def get(self):
226 options = {}
227 user = self.get_current_user()
228 if not user:
229 self.redirect('/auth/twitter/')
230 return
231 options['user'] = user
232 self.render('test.html', **options)
9ff6e88a »
2011-08-26 adding thing about dotjs
233
234 @route(r'/dotjs', name='dotjs')
235 class DotJSHandler(BaseHandler):
236
237 def get(self):
238 options = {}
239 user = self.get_current_user()
240 self.render('dotjs.html', **options)
241
242
243 @route(r'/download/twitter.com.js')
244 class DotJSHandler(BaseHandler):
245
246 def get(self):
247 import os
248 parent = os.path.abspath(os.path.dirname(__file__))
249 dir_ = os.path.join(parent, 'dotjs')
250 filepath = os.path.join(parent, 'dotjs', 'twitter.com.js')
251 assert os.path.isfile(filepath)
252 self.set_header('Content-Type', 'application/octet-stream')
253 self.set_header('Content-Disposition',
254 'attachment;filename="%s"' %
255 os.path.basename(filepath))
256 with file(filepath) as f:
257 self.write(f.read())
f0a8efdc »
2011-08-29 changing to a bookmarklet
258
259
260 @route('/following/(\w+)')
261 class FollowingHandler(BaseHandler, tornado.auth.TwitterMixin):
262
263 @tornado.web.asynchronous
264 def get(self, username):
265 options = {'username': username}
266 user = self.get_current_user()
267 if not user:
268 self.redirect('auth_twitter')
269 return
270 this_username = self.get_current_user()
271 options['follows'] = None
272 if this_username:
273 key = 'follows:%s:%s' % (this_username, username)
274 value = self.redis.get(key)
275 if value is None:
276 access_token = self.redis.get('username:%s' % this_username)
277 access_token = json_decode(access_token)
278 self.twitter_request(
279 "/friendships/show",
280 source_screen_name=this_username,
281 target_screen_name=username,
282 access_token=access_token,
283 callback=self.async_callback(
284 lambda x: self._on_show(x, this_username, username, options)
285 ),
286 )
287 return
288 options['follows'] = bool(int(value))
289 self.render('following.html', **options)
290
291 def _on_show(self, result, this_username, username, options):
292 value = None
293 if result and 'relationship' in result:
294 value = result['relationship']['target']['following']
295 key = 'follows:%s:%s' % (this_username, username)
296 self.redis.setex(key, int(bool(value)), 60)
297 options['follows'] = value
298 self.render('following.html', **options)
Something went wrong with that request. Please try again.