PageRenderTime 27ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/controller.py

https://bitbucket.org/macfri/find-gift
Python | 477 lines | 448 code | 27 blank | 2 comment | 6 complexity | 7eb21355b5a4d8622c42adfdb9dc3863 MD5 | raw file
  1. import hmac
  2. import urllib
  3. import base64
  4. import hashlib
  5. import logging
  6. import settings
  7. import simplejson
  8. import tasks
  9. import cPickle
  10. import memcache
  11. from models import Gift, User, UserGift
  12. from tornado.web import RequestHandler, HTTPError
  13. from sqlalchemy import create_engine, orm
  14. from sqlalchemy.sql import and_, between
  15. engine = create_engine(settings.DATABASE_DSN)
  16. Session = orm.sessionmaker(bind=engine)()
  17. mc = memcache.Client(['127.0.0.1:11211'], debug=0)
  18. AGES = (
  19. ('13-17', '13-17'),
  20. ('18-24', '18-24'),
  21. ('25-34', '25-34'),
  22. ('35-44', '35-44'),
  23. ('45-54', '45-54'),
  24. ('55-0', '+55'),
  25. )
  26. GENDER = (
  27. ('male', 'Masculino'),
  28. ('female', 'Femenino')
  29. )
  30. PRICES = (
  31. ('0-50', 'S/.0-50'),
  32. ('50-100', 'S/.50-100'),
  33. ('100-150', 'S/.100-150'),
  34. ('150-200', 'S/.150-200'),
  35. ('200-250', 'S/.200-250'),
  36. ('250-300', 'S/.250-300'),
  37. ('300-0', 'S/.300+')
  38. )
  39. CATEGORIES = (
  40. ('perfumeria-maquillaje', 'Perfumeria y Maquillaje'),
  41. ('mujer', 'Mujer'),
  42. ('juvenil', 'Juvenil'),
  43. ('hombre', 'Hombre'),
  44. ('ninos', 'Ninos'),
  45. ('oportunidades', 'Oportunidades unicas')
  46. )
  47. def pagination(limit, page):
  48. if not page.isdigit():
  49. page = int(page)
  50. else:
  51. page = 1
  52. offset = ((page - 1) * limit)
  53. return (limit, offset)
  54. def base64_url_decode(inp):
  55. padding_factor = (4 - len(inp) % 4) % 4
  56. inp += "=" * padding_factor
  57. return base64.b64decode(unicode(inp).translate(
  58. dict(zip(map(ord, u'-_'), u'+/'))))
  59. def tags(user_id, friend_id, token):
  60. connectors = (
  61. 'books',
  62. 'games',
  63. 'likes',
  64. 'music',
  65. 'movies',
  66. 'interests',
  67. 'television',
  68. 'activities'
  69. )
  70. for connector in connectors:
  71. tasks.tags.delay(user_id, connector, friend_id, token)
  72. def multiquery_kwords(friend_id, items):
  73. tmp_queries = []
  74. for x in items:
  75. #sku = x.get('sku')
  76. sku = x.sku
  77. #keywords = x.get('keywords')
  78. keywords = x.keywords.split(',')
  79. kwors = ''
  80. tmp_keywords_sql = []
  81. for k in keywords:
  82. tmp_keywords_sql.append(
  83. "strpos(lower(message), '%s') >= 0" % k.lower())
  84. if tmp_keywords_sql:
  85. kwors = ' or '.join(tmp_keywords_sql)
  86. kwors = ' and (%s)' % kwors
  87. tmp_queries.append(
  88. '"%s": "select uid from status where uid=%s %s"' % (
  89. sku, friend_id, kwors))
  90. url = ','.join(tmp_queries)
  91. q = '{%s}' % url
  92. return q
  93. def load_data_url(url, params, json=True):
  94. try:
  95. data = urllib.urlopen('%s?%s' % (
  96. url, urllib.urlencode(params))).read()
  97. if json:
  98. data = simplejson.loads(data)
  99. except Exception as exc:
  100. logging.error(exc)
  101. data = None
  102. return data
  103. def parse_signed_request(signed_request, secret):
  104. l = signed_request .split('.', 2)
  105. encoded_sig = l[0]
  106. payload = l[1]
  107. sig = base64_url_decode(encoded_sig)
  108. data = simplejson.loads(base64_url_decode(payload))
  109. if data.get('algorithm').upper() != 'HMAC-SHA256':
  110. logging.error('Unknown algorithm')
  111. return None
  112. else:
  113. expected_sig = hmac.new(
  114. secret, msg=payload, digestmod=hashlib.sha256
  115. ).digest()
  116. if sig != expected_sig:
  117. return None
  118. else:
  119. return data
  120. def js_windows_location(url):
  121. return "<script>top.location.href='%s'</script>" % url
  122. class BaseHandler(RequestHandler):
  123. def __init__(self, *args, **kwargs):
  124. super(BaseHandler, self).__init__(*args, **kwargs)
  125. def render_string(self, template, **kwargs):
  126. kwargs.update({'handler': self})
  127. return self.settings.get('template_env')\
  128. .get_template(template).render(**kwargs)
  129. def render(self, template, **kwargs):
  130. self.finish(self.render_string(template, **kwargs))
  131. class Index(BaseHandler):
  132. def post(self):
  133. self.clear_cookie('user')
  134. signed_request = self.get_argument('signed_request', None)
  135. if signed_request:
  136. user = parse_signed_request(signed_request, settings.API_SECRET)
  137. else:
  138. user = None
  139. if not user or not 'user_id' in user:
  140. permissions = (
  141. 'email',
  142. 'friends_likes',
  143. 'friends_activities',
  144. 'friends_interests',
  145. 'friends_birthday',
  146. 'read_stream',
  147. )
  148. params = dict(
  149. client_id=settings.API_KEY,
  150. redirect_uri=settings.CANVAS_PAGE,
  151. scope=','.join(permissions)
  152. )
  153. url = '%s?%s' % (settings.FACEBOOK_OAUTH, urllib.urlencode(params))
  154. logging.info('url: %s' % url)
  155. self.write(js_windows_location(url))
  156. else:
  157. data = cPickle.dumps({
  158. 'user_id': user['user_id'],
  159. 'access_token': user['oauth_token']
  160. }, -1)
  161. self.set_secure_cookie('user', data)
  162. limit, offset = pagination(9, self.get_argument('page', '1'))
  163. params = dict(
  164. access_token=user['oauth_token'],
  165. fields='picture,name',
  166. limit=limit,
  167. offset=offset
  168. )
  169. data = load_data_url(
  170. url='%s/me/friends' % settings.FACEBOOK_GRAPH,
  171. params=params,
  172. json=True
  173. )
  174. user_data = load_data_url(
  175. url='%s/%s' % (settings.FACEBOOK_GRAPH, user.get('user_id')),
  176. params={'access_token': user.get('oauth_token')},
  177. json=True
  178. )
  179. user2 = Session.query(User).filter_by(
  180. email=user_data.get('email')).first()
  181. if not user2:
  182. user2 = User()
  183. user2.email = user_data.get('email')
  184. user2.fbid = user_data.get('id')
  185. Session.add(user2)
  186. Session.commit()
  187. self.render('index.html', data=data.get('data'))
  188. class ListGift(BaseHandler):
  189. def post(self):
  190. cookie = self.get_secure_cookie('user')
  191. if cookie:
  192. user = cPickle.loads(cookie)
  193. else:
  194. user = None
  195. if not user:
  196. raise HTTPError(500, "Auth failed")
  197. user = Session.query(User).filter_by(
  198. fbid=user.get('user_id')).first()
  199. self.render('list.html', user=user)
  200. class AddGift(BaseHandler):
  201. def post(self):
  202. cookie = self.get_secure_cookie('user')
  203. if cookie:
  204. user = cPickle.loads(cookie)
  205. else:
  206. user = None
  207. if not user:
  208. raise HTTPError(500, "Auth failed")
  209. friend_id = self.get_argument('friend_id', None)
  210. gift_id = self.get_argument('gift_id', None)
  211. user2 = Session.query(User).filter_by(fbid=user.get('user_id')).first()
  212. gift2 = Session.query(Gift).filter(Gift.id == gift_id).first()
  213. exists = Session.query(UserGift).filter(and_(
  214. UserGift.user_id == user2.id,
  215. UserGift.gift_id == gift_id,
  216. UserGift.friend_id == friend_id
  217. )).first()
  218. if not exists and gift2 and user2:
  219. try:
  220. user_gift = UserGift()
  221. user_gift.friend_id = friend_id
  222. user_gift.gift = gift2
  223. user_gift.user = user2
  224. user2.gifts.append(user_gift)
  225. Session.add(user2)
  226. Session.commit()
  227. except Exception as exc:
  228. Session.rollback()
  229. logging.error(exc)
  230. else:
  231. logging.info('exists')
  232. class FindGift(BaseHandler):
  233. def get(self, friend_id):
  234. cookie = self.get_secure_cookie('user')
  235. mc.delete(str(friend_id))
  236. if cookie:
  237. user = cPickle.loads(cookie)
  238. else:
  239. user = None
  240. if not user:
  241. raise HTTPError(500, "Auth failed")
  242. items = Session.query(Gift).all()
  243. params = dict(
  244. q=multiquery_kwords(friend_id, items),
  245. access_token=user.get('access_token')
  246. )
  247. data = load_data_url(
  248. url='%s/fql' % settings.FACEBOOK_GRAPH,
  249. params=params,
  250. json=True
  251. )
  252. skus = []
  253. for x in data.get('data'):
  254. if x.get('fql_result_set'):
  255. skus.append(x.get('name'))
  256. mc.set(str(friend_id), ','.join([str(x) for x in skus]))
  257. logging.info(data)
  258. friend_data = load_data_url(
  259. url='%s/%s' % (settings.FACEBOOK_GRAPH, friend_id),
  260. params={'access_token': user.get('access_token')},
  261. json=True
  262. )
  263. if 'birthday' in friend_data:
  264. has_birthday = True
  265. else:
  266. has_birthday = True
  267. if 'gender' in friend_data:
  268. has_gender = False
  269. else:
  270. has_gender = True
  271. logging.info(friend_data)
  272. self.render('detail.html',
  273. ages=AGES,
  274. prices=PRICES,
  275. gender=GENDER,
  276. categories=CATEGORIES,
  277. has_birthday=has_birthday,
  278. has_gender=has_gender,
  279. friend_id=friend_id
  280. )
  281. def post(self, friend_id):
  282. cookie = self.get_secure_cookie('user')
  283. if cookie:
  284. user = cPickle.loads(cookie)
  285. else:
  286. user = None
  287. if not user:
  288. raise HTTPError(500, "Auth failed")
  289. price = self.get_argument('price', None)
  290. gender = self.get_argument('gender', None)
  291. category = self.get_argument('category', None)
  292. age = self.get_argument('age', None)
  293. price = '50-100'
  294. gender = 'male'
  295. category = 'oportunidades'
  296. age = '13-17'
  297. logging.info('price: %s' % price)
  298. logging.info('gender: %s' % gender)
  299. logging.info('category: %s' % category)
  300. logging.info('age: %s' % age)
  301. has_birthday = True
  302. has_gender = False
  303. skus = mc.get(str(friend_id)).split(',')
  304. filters = [Gift.sku.in_(skus)]
  305. if age:
  306. left, right = [int(x) for x in age.split('-')]
  307. if left == 0 and right > 0:
  308. filters.append(Gift.age <= right)
  309. elif left > 0 and right == 0:
  310. filters.append(Gift.age >= left)
  311. else:
  312. filters.append(between(Gift.age, left, right))
  313. if price:
  314. left, right = [int(x) for x in price.split('-')]
  315. if left == 0 and right > 0:
  316. filters.append(Gift.price <= right)
  317. elif left > 0 and right == 0:
  318. filters.append(Gift.price >= left)
  319. else:
  320. filters.append(between(Gift.price, left, right))
  321. if category:
  322. filters.append(Gift.category == category)
  323. if gender:
  324. filters.append(Gift.gender == gender)
  325. items = Session.query(Gift).filter(*filters).all()
  326. logging.info(items)
  327. self.render('detail.html',
  328. ages=AGES,
  329. prices=PRICES,
  330. gender=GENDER,
  331. categories=CATEGORIES,
  332. has_birthday=has_birthday,
  333. has_gender=has_gender,
  334. items=items,
  335. friend_id=friend_id
  336. )