PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main.py

https://github.com/xgenvn/jupo
Python | 2964 lines | 2898 code | 46 blank | 20 comment | 45 complexity | 61aabd1f337c08fece12c14dd462cceb MD5 | raw file
Possible License(s): AGPL-3.0
  1. #! coding: utf-8
  2. # pylint: disable-msg=W0311, W0611, E1103, E1101
  3. #@PydevCodeAnalysisIgnore
  4. from raven.contrib.flask import Sentry
  5. from flask import (Flask, request,
  6. render_template, render_template_string,
  7. redirect, abort,
  8. url_for, session, g, flash,
  9. make_response, Response)
  10. from flask_sslify import SSLify
  11. from flask.ext.oauth import OAuth
  12. from flask.ext.seasurf import SeaSurf
  13. from flask.ext.assets import Bundle, Environment as WebAssets
  14. from werkzeug.wrappers import BaseRequest
  15. from werkzeug.utils import cached_property
  16. from werkzeug.contrib.securecookie import SecureCookie
  17. from werkzeug.contrib.profiler import ProfilerMiddleware, MergeStream
  18. from datetime import timedelta
  19. from commands import getoutput
  20. from mimetypes import guess_type
  21. from simplejson import dumps, loads
  22. from time import mktime, strptime, sleep
  23. from urlparse import urlparse, urlunparse
  24. from jinja2 import Environment
  25. from werkzeug.contrib.cache import MemcachedCache
  26. from lib import cache
  27. from lib.img_utils import zoom
  28. from lib.json_util import default as BSON
  29. from helpers import extensions
  30. from helpers.decorators import *
  31. from helpers.converters import *
  32. import os
  33. import sys
  34. import logging
  35. import requests
  36. import traceback
  37. import werkzeug.serving
  38. import flask_debugtoolbar
  39. from flask_debugtoolbar_lineprofilerpanel.profile import line_profile
  40. import api
  41. import filters
  42. import settings
  43. from app import CURRENT_APP, render
  44. # switch from the default ASCII to UTF-8 encoding
  45. reload(sys)
  46. sys.setdefaultencoding("utf-8") #@UndefinedVariable
  47. requests.adapters.DEFAULT_RETRIES = 3
  48. app = CURRENT_APP
  49. assets = WebAssets(app)
  50. if settings.SENTRY_DSN:
  51. sentry = Sentry(app, dsn=settings.SENTRY_DSN, logging=False)
  52. csrf = SeaSurf(app)
  53. oauth = OAuth()
  54. @line_profile
  55. def render_homepage(session_id, title, **kwargs):
  56. """ Render homepage for signed in user """
  57. if session_id:
  58. user_id = api.get_user_id(session_id)
  59. if user_id:
  60. owner = api.get_user_info(user_id)
  61. else:
  62. owner = None
  63. else:
  64. owner = None
  65. if owner:
  66. friends_online = [i for i in owner.contacts \
  67. if i.status in ['online', 'away']]
  68. friends_online.sort(key=lambda k: k.last_online, reverse=True)
  69. if not kwargs.has_key('groups'):
  70. groups = api.get_groups(session_id, limit=3)
  71. else:
  72. groups = kwargs.pop('groups')
  73. for group in groups[:3]:
  74. group.unread_posts = api.get_unread_posts_count(session_id, group.id)
  75. unread_messages = api.get_unread_messages(session_id)
  76. unread_messages_count = sum([i.get('unread_count') for i in unread_messages])
  77. unread_notification_count = api.get_unread_notifications_count(session_id)\
  78. + unread_messages_count
  79. else:
  80. friends_online = []
  81. groups = []
  82. unread_messages = []
  83. unread_messages_count = 0
  84. unread_notification_count = 0
  85. if kwargs.has_key('stats'):
  86. stats = kwargs.pop('stats')
  87. else:
  88. stats = {}
  89. hostname = request.headers.get('Host')
  90. logo_text = 'Jupo'
  91. if hostname != settings.PRIMARY_DOMAIN:
  92. network_info = api.get_network_info(hostname.replace('.', '_'))
  93. if network_info and network_info.has_key('name'):
  94. logo_text = network_info['name']
  95. resp = Response(render_template('home.html',
  96. owner=owner,
  97. title=title,
  98. groups=groups,
  99. friends_online=friends_online,
  100. unread_messages=unread_messages,
  101. unread_messages_count=unread_messages_count,
  102. unread_notification_count=unread_notification_count,
  103. stats=stats,
  104. debug=settings.DEBUG,
  105. logo_text=logo_text,
  106. domain=hostname,
  107. **kwargs))
  108. if owner:
  109. resp.set_cookie('channel_id', api.get_channel_id(session_id))
  110. else:
  111. resp.delete_cookie('channel_id')
  112. # disallows rendering of the document when inside an iframe
  113. # http://javascript.info/tutorial/clickjacking
  114. resp.headers['X-Frame-Options'] = 'DENY'
  115. return resp
  116. def event_stream(channel):
  117. pubsub = api.PUBSUB.pubsub()
  118. pubsub.subscribe(channel)
  119. for message in pubsub.listen():
  120. yield 'retry: 100\ndata: %s\n\n' % message['data']
  121. #===============================================================================
  122. # URL routing and handlers
  123. #===============================================================================
  124. @app.route('/ping')
  125. def ping():
  126. session_id = session.get('session_id')
  127. if session_id:
  128. api.update_pingpong_timestamp(session_id)
  129. return 'pong'
  130. @app.route('/stream')
  131. def stream():
  132. session_id = session.get('session_id')
  133. if not session_id:
  134. abort(400)
  135. channel_id = request.cookies.get('channel_id')
  136. resp = Response(event_stream(channel_id),
  137. mimetype="text/event-stream")
  138. resp.headers['X-Accel-Buffering'] = 'no'
  139. return resp
  140. @csrf.exempt
  141. @app.route("/autocomplete")
  142. @line_profile
  143. def autocomplete():
  144. session_id = session.get("session_id")
  145. query = request.args.get('query')
  146. type = request.args.get('type')
  147. if not query: # preload all groups & coworkers
  148. owners = api.get_contacts(session_id)
  149. user_ids = [i.id for i in owners]
  150. for user in api.get_all_users():
  151. if user.id not in user_ids:
  152. user_ids.append(user.id)
  153. owners.append(user)
  154. if type != 'user':
  155. groups = api.get_groups(session_id)
  156. group_ids = [i.id for i in groups]
  157. owners.extend(groups)
  158. items = [{'id': 'public',
  159. 'name': 'Public',
  160. 'avatar': '/public/images/public-group.png',
  161. 'type': 'group'}]
  162. for group in api.get_all_groups():
  163. if group.id not in group_ids:
  164. group_ids.append(group.id)
  165. owners.append(group)
  166. else:
  167. items = []
  168. for i in owners:
  169. if i.is_group():
  170. info = {'name': i.name,
  171. 'id': str(i.id),
  172. 'avatar': '/public/images/group-icon2.png',
  173. 'type': 'group'}
  174. items.append(info)
  175. else:
  176. names = [i.name]
  177. for name in names:
  178. info = {'name': name,
  179. 'id': str(i.id),
  180. 'avatar': i.avatar,
  181. 'type': 'user'}
  182. items.append(info)
  183. else:
  184. if type == 'user': # mentions
  185. _items = api.autocomplete(session_id, query)
  186. items = []
  187. for item in _items:
  188. if not api.is_group(item.get('id')): # only show user, not group
  189. info = api.get_user_info(item.get('id'))
  190. avatar = info.avatar
  191. type = 'user'
  192. items.append({'id': str(item.get('id')),
  193. 'name': item.get('name', item.get('email')),
  194. 'avatar': avatar,
  195. 'type': type})
  196. else:
  197. _items = api.autocomplete(session_id, query)
  198. items = []
  199. for item in _items:
  200. info = api.get_owner_info_from_uuid(item.get('id'))
  201. avatar = '/public/images/group.png' if info.is_group() else info.avatar
  202. items.append({'id': str(item.get('id')),
  203. 'name': item.get('name', item.get('email')),
  204. 'avatar': avatar,
  205. 'type': item.get('type')})
  206. # emoticons = [{'id': 'happy',
  207. # 'type': 'emoticon',
  208. # 'name': 'happy',
  209. # 'avatar': 'https://5works.s3.amazonaws.com/emoticons/1.gif'},
  210. # {'id': 'sad',
  211. # 'type': 'emoticon',
  212. # 'name': 'sad',
  213. # 'avatar': 'https://5works.s3.amazonaws.com/emoticons/2.gif'},
  214. # ]
  215. # items.extend(emoticons)
  216. return dumps(items)
  217. @app.route("/search", methods=['GET', 'OPTIONS', 'POST'])
  218. @login_required
  219. @line_profile
  220. def search():
  221. t0 = api.utctime()
  222. session_id = session.get("session_id")
  223. query = request.form.get('query', request.args.get('query', '')).strip()
  224. item_type = request.args.get('type')
  225. page = int(request.args.get('page', 1))
  226. ref_user_id = request.args.get('user')
  227. ref = request.args.get('ref')
  228. if ref and 'group-' in ref:
  229. group_id = ref.split('-')[1]
  230. group = api.get_group_info(session_id, group_id)
  231. if item_type == 'people':
  232. title = 'Add people to group'
  233. else:
  234. title = 'Invite your friends'
  235. elif ref == 'everyone':
  236. title = 'Invite your friends'
  237. group_id = group = None
  238. else:
  239. group_id = group = None
  240. title = 'Add Contacts'
  241. user_id = api.get_user_id(session_id)
  242. owner = api.get_user_info(user_id)
  243. if item_type in ['people', 'email']:
  244. if request.method == 'OPTIONS':
  245. if query:
  246. if item_type == 'people':
  247. users = api.people_search(query, group_id)
  248. if users:
  249. users = [i for i in users \
  250. if i.id not in owner.contact_ids and i.id != owner.id]
  251. else:
  252. users = [i for i in api.get_coworkers(session_id) \
  253. if i.id not in group.member_ids and i.id != owner.id]
  254. else:
  255. users = [i for i in owner.google_contacts \
  256. if api.get_user_id_from_email_address(i.email) not in group.member_ids]
  257. elif group_id:
  258. if item_type == 'email':
  259. users = [i for i in owner.google_contacts \
  260. if api.get_user_id_from_email_address(i.email) not in group.member_ids]
  261. else:
  262. users = [i for i in api.get_coworkers(session_id) \
  263. if i.id not in group.member_ids and i.id != owner.id]
  264. else:
  265. if item_type == 'email':
  266. users = [i for i in owner.google_contacts]
  267. else:
  268. users = [i for i in api.get_coworkers(session_id) \
  269. if i.id not in owner.contact_ids and i.id != owner.id]
  270. return dumps({'title': title,
  271. 'body': render_template('people_search.html',
  272. title=title,
  273. mode='search',
  274. type=item_type,
  275. group_id=group_id,
  276. group=group,
  277. users=users,
  278. query=query,
  279. owner=owner)})
  280. else:
  281. if item_type == 'people':
  282. users = api.people_search(query)
  283. else:
  284. q = query.lower()
  285. users = [i for i in owner.google_contacts \
  286. if i.email and i.email.lower().startswith(q)]
  287. if group_id:
  288. out = [i for i in users if i.email and i.id not in group.member_ids and i.id != owner.id]
  289. out.extend([i for i in users if i.email and i.id != owner.id and i.id in group.member_ids])
  290. users = out
  291. else:
  292. users = [i for i in users if i.email]
  293. if users:
  294. return ''.join(render_template('user.html',
  295. mode='search',
  296. user=user,
  297. group_id=group_id,
  298. group=group,
  299. type=item_type,
  300. query=query,
  301. owner=owner,
  302. title=title) \
  303. for user in users if user.email)
  304. else:
  305. if item_type == 'email':
  306. return "<li>Type your friend's email address</li>"
  307. else:
  308. return "<li>0 results found</li>"
  309. # search posts
  310. results = api.search(session_id, query, item_type,
  311. ref_user_id=ref_user_id, page=page)
  312. if results and results.has_key('counters'):
  313. hits = results.get('hits', 0)
  314. total = sum([i['count'] for i in results.get('counters')])
  315. counters = results['counters']
  316. else:
  317. hits = 0
  318. total = 0
  319. counters = {}
  320. due = api.utctime() - t0
  321. owner = api.get_owner_info(session_id)
  322. coworkers = api.get_coworkers(session_id)
  323. if request.method == 'GET':
  324. return render_homepage(session_id, 'Results for "%s"' % query,
  325. query=query,
  326. type=item_type,
  327. due='%.3f' % due,
  328. total=total,
  329. hits=hits,
  330. coworkers=coworkers,
  331. user=user,
  332. view='results',
  333. page=page,
  334. counters=counters)
  335. if page == 1:
  336. body = render_template('results.html', owner=owner,
  337. query=query,
  338. type=item_type,
  339. due='%.3f' % due,
  340. total=total,
  341. hits=hits,
  342. coworkers=coworkers,
  343. user=user,
  344. view='results',
  345. page=page,
  346. counters=counters)
  347. else:
  348. posts = [render(hits, "feed", owner, 'results')]
  349. if len(hits) == 0:
  350. posts.append(render_template('more.html', more_url=None))
  351. else:
  352. more_url = '/search?query=%s&page=%s' % (query, page+1)
  353. if item_type:
  354. more_url += '&type=%s' % item_type
  355. if user:
  356. more_url += '&user=%s' % user
  357. posts.append(render_template('more.html', more_url=more_url))
  358. return ''.join(posts)
  359. # TODO: render 1 lần thôi :(
  360. if body.split('<ul id="stream">')[-1].split('<script>')[0].split('right-sidebar')[0].count(query) < 2:
  361. spelling_suggestion = api.get_spelling_suggestion(query)
  362. app.logger.debug('spelling suggestion: %s' % spelling_suggestion)
  363. body = render_template('results.html', owner=owner,
  364. spelling_suggestion=spelling_suggestion,
  365. query=query,
  366. type=item_type,
  367. due='%.3f' % due,
  368. total=total,
  369. hits=hits,
  370. coworkers=coworkers,
  371. user=user,
  372. view='results',
  373. counters=counters)
  374. json = dumps({'title': '%s - Jupo Search' % query,
  375. 'body': body})
  376. return Response(json, content_type='application/json')
  377. #@app.route("/", methods=["GET", "OPTIONS"])
  378. @app.route('/<any(discover, starred, hot, incoming, shared_by_me):name>', methods=['GET', 'OPTIONS'])
  379. @app.route('/<any(discover, starred, hot, incoming, shared_by_me):name>/page<int:page>', methods=['OPTIONS'])
  380. def discover(name='discover', page=1):
  381. code = request.args.get('code')
  382. user_id = api.get_user_id(code)
  383. if user_id:
  384. session['session_id'] = code
  385. return render_homepage(code, 'Complete Profile',
  386. code=code, user_id=user_id)
  387. session_id = session.get("session_id")
  388. app.logger.debug('session_id: %s' % session_id)
  389. user_id = api.get_user_id(session_id)
  390. if user_id:
  391. owner = api.get_user_info(user_id)
  392. if name == 'starred':
  393. category = name
  394. feeds = api.get_starred_posts(session_id, page=page)
  395. elif name == 'hot':
  396. category = name
  397. feeds = api.get_hot_posts(page=page)
  398. elif name == 'shared_by_me':
  399. category = name
  400. feeds = api.get_shared_by_me_posts(session_id, page=page)
  401. elif request.path in ['/', '/incoming', '/discover']:
  402. # feeds = api.get_incoming_posts(session_id, page=page)
  403. feeds = api.get_discover_posts(session_id, page=page)
  404. # feeds = api.get_public_posts(session_id=session_id, page=page)
  405. category = None
  406. else:
  407. feeds = api.get_public_posts(session_id=session_id, page=page)
  408. category = None
  409. else:
  410. feeds = api.get_public_posts(session_id=session_id, page=page)
  411. owner = category = None
  412. if session.has_key('session_id'):
  413. session.pop('session_id')
  414. public_groups = api.get_open_groups(limit=10)
  415. if request.method == 'OPTIONS':
  416. if page == 1:
  417. menu = render_template('menu.html',
  418. owner=owner,
  419. category=category,
  420. view='discover')
  421. body = render_template('discover.html',
  422. view='discover',
  423. category=category,
  424. public_groups=public_groups,
  425. owner=owner,
  426. title='Discover',
  427. feeds=feeds)
  428. json = dumps({"body": body,
  429. "menu": menu,
  430. "title": 'Discover'})
  431. resp = Response(json, mimetype='application/json')
  432. return resp
  433. else:
  434. posts = []
  435. for feed in feeds:
  436. posts.append(render(feed, "feed", owner, 'discover'))
  437. if len(feeds) == 0:
  438. posts.append(render_template('more.html', more_url=None))
  439. else:
  440. posts.append(render_template('more.html',
  441. more_url='/%s/page%d' \
  442. % (request.path.split('/')[1], page+1)))
  443. return ''.join(posts)
  444. else:
  445. if not user_id:
  446. # return render_homepage(session_id, 'Get work done. Faster. | Jupo',
  447. # view='intro')
  448. return render_template('landing_page.html')
  449. else:
  450. return render_homepage(session_id, 'Discover',
  451. view='discover',
  452. feeds=feeds)
  453. @app.route('/invite', methods=['GET', 'POST'])
  454. def invite():
  455. email = request.form.get('email', request.args.get('email'))
  456. group_id = request.form.get('group_id', request.args.get('group_id'))
  457. session_id = session.get("session_id")
  458. api.invite(session_id, email, group_id)
  459. return ' ✔ Done '
  460. @app.route('/welcome', methods=['GET', 'OPTIONS'])
  461. def welcome():
  462. if request.method == 'GET':
  463. session_id = session.get("session_id")
  464. return render_homepage(session_id, 'Getting Started', view='welcome')
  465. else:
  466. body = render_template('welcome.html', view='welcome')
  467. return dumps({'body': body,
  468. 'title': 'Welcome to Jupo'})
  469. @app.route('/privacy')
  470. def privacy():
  471. return redirect('https://www.jupo.com/note/340925645733232641')
  472. @app.route('/terms')
  473. def terms():
  474. return redirect('https://www.jupo.com/note/340921286333038593')
  475. @app.route('/about')
  476. def about():
  477. return render_template('about.html')
  478. @app.route('/notify_me', methods=['POST'])
  479. def notify_me():
  480. email = request.form.get('email')
  481. if not email:
  482. abort(400, 'Missing email')
  483. state = api.notify_me(email)
  484. return 'Thank you!'
  485. @app.route('/jobs')
  486. def jobs():
  487. return render_template('jobs_v2.html', title='Jupo - Jobs')
  488. @app.route("/<any(sign_in, sign_up, sign_out, forgot_password, reset_password):action>", methods=["GET", "OPTIONS", "POST"])
  489. def authentication(action=None):
  490. hostname = request.headers.get('Host')
  491. db_name = hostname.replace('.', '_')
  492. primary_domain = '.'.join(settings.PRIMARY_DOMAIN.rsplit('.', 2)[-2:])
  493. if hostname != settings.PRIMARY_DOMAIN:
  494. network_info = api.get_network_info(db_name)
  495. else:
  496. network_info = {'name': 'Jupo'}
  497. if request.path.endswith('sign_in'):
  498. if request.method == 'OPTIONS':
  499. data = dumps({'title': 'Sign in to Jupo',
  500. 'body': render_template('sign_in.html',
  501. domain=hostname,
  502. PRIMARY_DOMAIN=settings.PRIMARY_DOMAIN)})
  503. resp = Response(data, mimetype='application/json')
  504. return resp
  505. elif request.method == "GET":
  506. resp = Response(render_template('sign_in.html',
  507. domain=hostname,
  508. PRIMARY_DOMAIN=settings.PRIMARY_DOMAIN,
  509. network_info=network_info))
  510. return resp
  511. email = request.form.get("email")
  512. password = request.form.get("password")
  513. back_to = request.form.get('back_to', request.args.get('back_to'))
  514. user_agent = request.environ.get('HTTP_USER_AGENT')
  515. app.logger.debug(user_agent)
  516. remote_addr = request.environ.get('REMOTE_ADDR')
  517. session_id = api.sign_in(email, password,
  518. user_agent=user_agent, remote_addr=remote_addr)
  519. app.logger.debug(session_id)
  520. if session_id:
  521. # Sign in for all networks
  522. if db_name:
  523. db_names = api.get_db_names(email)
  524. if db_name not in db_names:
  525. api.add_db_name(email, db_name)
  526. for db in db_names:
  527. if db != db_name:
  528. api.update_session_id(email, session_id, db)
  529. session.permanent = True
  530. session['session_id'] = session_id
  531. if back_to:
  532. resp = redirect(back_to)
  533. resp.set_cookie('channel_id', api.get_channel_id(session_id))
  534. else:
  535. resp = redirect('/news_feed')
  536. resp.set_cookie('channel_id', api.get_channel_id(session_id))
  537. return resp
  538. else:
  539. message = 'Wrong email address and password combination.'
  540. resp = redirect('/?email=%s&message=%s' % (email, message))
  541. resp.set_cookie('new_user', '0')
  542. return resp
  543. elif request.path.endswith('sign_up'):
  544. if request.method == 'GET':
  545. welcome = request.args.get('welcome')
  546. resp = Response(render_template('sign_up.html',
  547. welcome=welcome,
  548. domain=hostname,
  549. PRIMARY_DOMAIN=settings.PRIMARY_DOMAIN,
  550. network_info=network_info))
  551. return resp
  552. email = request.form.get('email').strip()
  553. name = request.form.get('name')
  554. password = request.form.get('password', '')
  555. alerts = {}
  556. if email and api.is_exists(email):
  557. alerts['email'] = '"%s" is already in use.' % email
  558. if len(password) < 6:
  559. alerts['password'] = 'Your password must be at least 6 characters long.'
  560. if alerts.keys():
  561. data = dumps(alerts)
  562. return Response(data, mimetype='application/json')
  563. else:
  564. session_id = api.sign_up(email, password, name)
  565. if session_id:
  566. # Sign in for all networks
  567. if db_name:
  568. db_names = api.get_db_names(email)
  569. if db_name not in db_names:
  570. api.add_db_name(email, db_name)
  571. for db in db_names:
  572. if db != db_name:
  573. api.update_session_id(email, session_id, db)
  574. session['session_id'] = session_id
  575. return redirect('/reminders')
  576. else:
  577. return redirect('/')
  578. elif request.path.endswith('sign_out'):
  579. session_id = session.get('session_id')
  580. if session_id:
  581. user_id = api.get_user_id(session_id)
  582. email = api.get_user_info(user_id).email
  583. app.logger.debug('sign out: %s' % session_id)
  584. api.set_status(session_id, 'offline')
  585. api.sign_out(session_id)
  586. session.pop('session_id')
  587. # Sign out all networks
  588. if db_name:
  589. db_names = api.get_db_names(email)
  590. if db_name not in db_names:
  591. api.add_db_name(email, db_name)
  592. for db in db_names:
  593. if db != db_name:
  594. api.sign_out(session_id, db_name=db)
  595. return redirect('/')
  596. elif request.path.endswith('forgot_password'):
  597. if request.method == 'GET':
  598. return render_template('reset_password.html')
  599. if request.method == 'OPTIONS':
  600. data = dumps({'title': 'Jupo - Forgot your password?',
  601. 'body': render_template('forgot_password.html')})
  602. return Response(data, mimetype='application/json')
  603. else:
  604. email = request.form.get('email')
  605. if not email:
  606. abort(400)
  607. api.forgot_password(email)
  608. return redirect("/?message=Please check your inbox and follow the instructions in the email")
  609. elif request.path.endswith('reset_password'):
  610. if request.method == 'GET':
  611. code = request.args.get('code')
  612. if not code:
  613. return redirect('/news_feed')
  614. email = api.FORGOT_PASSWORD.get(code)
  615. if email:
  616. resp = {'title': 'Reset your password',
  617. 'body': render_template('reset_password.html',
  618. email=email, code=code)}
  619. return render_homepage(None, 'Reset your password',
  620. view='reset_password', email=email, code=code)
  621. return redirect('/?message=Link expired')
  622. else:
  623. code = request.form.get('code')
  624. new_password = request.form.get('password')
  625. if not code or not new_password:
  626. abort(400)
  627. email = api.FORGOT_PASSWORD.get(code)
  628. if not email:
  629. abort(410)
  630. user_id = api.get_user_id_from_email_address(email)
  631. if not user_id:
  632. abort(400)
  633. else:
  634. api.reset_password(user_id, new_password)
  635. session_id = api.sign_in(email, new_password)
  636. session['session_id'] = session_id
  637. return redirect('/news_feed')
  638. @app.route('/oauth/google')
  639. def google_login():
  640. domain = request.args.get('domain', settings.PRIMARY_DOMAIN)
  641. return redirect('https://accounts.google.com/o/oauth2/auth?response_type=code&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+https://www.google.com/m8/feeds/&redirect_uri=%s&approval_prompt=auto&state=%s&client_id=%s&hl=en&from_login=1&as=-773fbbe34097e4fd&pli=1&authuser=0' \
  642. % (settings.GOOGLE_REDIRECT_URI, domain, settings.GOOGLE_CLIENT_ID))
  643. @app.route('/oauth/google/authorized')
  644. def google_authorized():
  645. code = request.args.get('code')
  646. domain = request.args.get('state', settings.PRIMARY_DOMAIN)
  647. # get access_token
  648. url = 'https://accounts.google.com/o/oauth2/token'
  649. resp = requests.post(url, data={'code': code,
  650. 'client_id': settings.GOOGLE_CLIENT_ID,
  651. 'client_secret': settings.GOOGLE_CLIENT_SECRET,
  652. 'redirect_uri': settings.GOOGLE_REDIRECT_URI,
  653. 'grant_type': 'authorization_code'})
  654. data = loads(resp.text)
  655. # app.logger.debug(data)
  656. # fetch user info
  657. url = 'https://www.googleapis.com/oauth2/v1/userinfo'
  658. resp = requests.get(url, headers={'Authorization': '%s %s' \
  659. % (data.get('token_type'),
  660. data.get('access_token'))})
  661. user = loads(resp.text)
  662. url = 'https://www.google.com/m8/feeds/contacts/default/full/?max-results=5000'
  663. resp = requests.get(url, headers={'Authorization': '%s %s' \
  664. % (data.get('token_type'),
  665. data.get('access_token'))})
  666. contacts = api.re.findall("address='(.*?)'", resp.text)
  667. if contacts:
  668. contacts = list(set(contacts))
  669. db_name = domain.lower().strip().replace('.', '_')
  670. session_id = api.sign_in_with_google(email=user.get('email'),
  671. name=user.get('name'),
  672. gender=user.get('gender'),
  673. avatar=user.get('picture'),
  674. link=user.get('link'),
  675. locale=user.get('locale'),
  676. verified=user.get('verified_email'),
  677. google_contacts=contacts,
  678. db_name=db_name)
  679. if db_name:
  680. email = user.get('email')
  681. if email:
  682. db_names = api.get_db_names(email)
  683. if db_name not in db_names:
  684. api.add_db_name(email, db_name)
  685. for db in db_names:
  686. if db != db_name:
  687. api.update_session_id(email, session_id, db)
  688. if domain == settings.PRIMARY_DOMAIN:
  689. session['session_id'] = session_id
  690. return redirect('/')
  691. else:
  692. url = 'http://%s/?session_id=%s' % (domain, session_id)
  693. resp = redirect(url)
  694. return resp
  695. if settings.FACEBOOK_APP_ID and settings.FACEBOOK_APP_SECRET:
  696. facebook = oauth.remote_app('facebook',
  697. base_url='https://graph.facebook.com/',
  698. request_token_url=None,
  699. access_token_url='/oauth/access_token',
  700. authorize_url='https://www.facebook.com/dialog/oauth',
  701. consumer_key=settings.FACEBOOK_APP_ID,
  702. consumer_secret=settings.FACEBOOK_APP_SECRET,
  703. request_token_params={'scope': 'email'}
  704. )
  705. @app.route('/oauth/facebook')
  706. def facebook_login():
  707. if not facebook:
  708. abort(501)
  709. # return facebook.authorize(callback='http://play.jupo.com/oauth/facebook/authorized')
  710. callback_url = url_for('facebook_authorized',
  711. domain=request.args.get('domain', settings.PRIMARY_DOMAIN),
  712. _external=True)
  713. app.logger.debug(callback_url)
  714. return facebook.authorize(callback=callback_url)
  715. @app.route('/oauth/facebook/authorized')
  716. @facebook.authorized_handler
  717. def facebook_authorized(resp):
  718. domain = request.args.get('domain', settings.PRIMARY_DOMAIN)
  719. if resp is None:
  720. return 'Access denied: reason=%s error=%s' % (request.args['error_reason'],
  721. request.args['error_description'])
  722. session['facebook_access_token'] = (resp['access_token'], '')
  723. if request.args.get('fb_source') == 'notification':
  724. return redirect('/')
  725. retry_count = 0
  726. while retry_count < 3:
  727. try:
  728. me = facebook.get('/me')
  729. break
  730. except:
  731. retry_count += 1
  732. sleep(1)
  733. retry_count = 0
  734. while retry_count < 3:
  735. try:
  736. friends = facebook.get('/me/friends?limit=5000')
  737. break
  738. except:
  739. retry_count += 1
  740. sleep(1)
  741. facebook_id = me.data['id']
  742. friend_ids = [i['id'] for i in friends.data['data'] if isinstance(i, dict)]
  743. db_name = domain.lower().strip().replace('.', '_')
  744. session_id = api.sign_in_with_facebook(email=me.data.get('email'),
  745. name=me.data.get('name'),
  746. gender=me.data.get('gender'),
  747. avatar='https://graph.facebook.com/%s/picture' % facebook_id,
  748. link=me.data.get('link'),
  749. locale=me.data.get('locale'),
  750. timezone=me.data.get('timezone'),
  751. verified=me.data.get('verified'),
  752. facebook_id=facebook_id,
  753. facebook_friend_ids=friend_ids,
  754. db_name=db_name)
  755. if db_name:
  756. email = me.data.get('email')
  757. if email:
  758. db_names = api.get_db_names(email)
  759. if db_name not in db_names:
  760. api.add_db_name(email, db_name)
  761. for db in db_names:
  762. if db != db_name:
  763. api.update_session_id(email, session_id, db)
  764. if domain == settings.PRIMARY_DOMAIN:
  765. session['session_id'] = session_id
  766. return redirect('/')
  767. else:
  768. url = 'http://%s/?session_id=%s' % (domain, session_id)
  769. resp = redirect(url)
  770. return resp
  771. @facebook.tokengetter
  772. def get_facebook_token():
  773. return session.get('facebook_access_token')
  774. @app.route('/reminders', methods=['GET', 'OPTIONS', 'POST'])
  775. @app.route('/reminder/new', methods=["POST"])
  776. @app.route('/reminder/<int:reminder_id>/check', methods=["POST"])
  777. @app.route('/reminder/<int:reminder_id>/uncheck', methods=["POST"])
  778. @login_required
  779. @line_profile
  780. def reminders(reminder_id=None):
  781. session_id = session.get("session_id")
  782. message = request.form.get('message')
  783. if request.path.endswith('/new'):
  784. id = api.new_reminder(session_id, message)
  785. return str(id)
  786. elif request.path.endswith('/check'):
  787. api.check(session_id, reminder_id)
  788. return 'Done'
  789. elif request.path.endswith('/uncheck'):
  790. api.uncheck(session_id, reminder_id)
  791. return 'Done'
  792. else:
  793. reminders_list = api.get_reminders(session_id)
  794. if request.method == 'GET':
  795. return render_homepage(session_id, 'Reminders',
  796. view='reminders',
  797. reminders=reminders_list)
  798. else:
  799. body = render_template('reminders.html',
  800. view='reminders',
  801. reminders=reminders_list)
  802. json = dumps({"body": body,
  803. "title": 'Reminders'})
  804. return Response(json, mimetype='application/json')
  805. @app.route("/notes", methods=['GET', 'OPTIONS'])
  806. @app.route("/notes/page<int:page>", methods=['OPTIONS'])
  807. @login_required
  808. @line_profile
  809. def notes(page=1):
  810. view = 'notes'
  811. session_id = session.get("session_id")
  812. user_id = api.get_user_id(session_id)
  813. owner = api.get_user_info(user_id)
  814. title = "Notes"
  815. notes = api.get_notes(session_id, page=page)
  816. if page == 1:
  817. reference_notes = api.get_reference_notes(session_id, 10)
  818. else:
  819. reference_notes = []
  820. app.logger.debug(notes)
  821. if request.method == "OPTIONS":
  822. if page > 1:
  823. stream = ''
  824. posts = []
  825. for note in notes:
  826. posts.append(render(note, "note", owner, view, request=request))
  827. if len(notes) == 0:
  828. posts.append(render_template('more.html', more_url=None))
  829. else:
  830. posts.append(render_template('more.html',
  831. more_url='/notes/page%d' % (page+1)))
  832. return ''.join(posts)
  833. else:
  834. menu = render_template('menu.html',
  835. view=view)
  836. body = render_template('notes.html',
  837. view=view,
  838. title=title,
  839. owner=owner,
  840. request=request,
  841. reference_notes=reference_notes,
  842. notes=notes)
  843. json = dumps({"body": body,
  844. "menu": menu,
  845. "title": title})
  846. return Response(json, mimetype='application/json')
  847. else:
  848. return render_homepage(session_id, title,
  849. view=view,
  850. request=request,
  851. reference_notes=reference_notes,
  852. notes=notes)
  853. @app.route("/note/new", methods=["GET", "OPTIONS", "POST"])
  854. @app.route("/note/<int:note_id>", methods=["GET", "OPTIONS"])
  855. @app.route("/note/<int:note_id>/edit", methods=["OPTIONS"])
  856. @app.route("/note/<int:note_id>/v<int:version>", methods=["OPTIONS", "POST"])
  857. @app.route("/note/<int:note_id>/<action>", methods=["GET", "OPTIONS", "POST"])
  858. @login_required
  859. def note(note_id=None, action=None, version=None):
  860. session_id = session.get("session_id")
  861. owner = api.get_owner_info(session_id)
  862. content = info = None
  863. if request.path == '/note/new':
  864. if request.method == 'GET':
  865. note = {}
  866. title = 'New Note'
  867. mode = 'edit'
  868. view = 'notes'
  869. return render_homepage(session_id, title,
  870. view=view,
  871. note=note, mode=mode)
  872. elif request.method == 'OPTIONS':
  873. title = 'New Note'
  874. mode = 'edit'
  875. note = {}
  876. else:
  877. title = request.form.get('title', 'Untitled Note')
  878. content = request.form.get('content')
  879. note_id = request.form.get('note_id')
  880. viewers = request.form.get('viewers')
  881. if viewers:
  882. viewers = viewers.split(',')
  883. else:
  884. viewers = []
  885. attachments = request.form.get('attachments')
  886. if attachments:
  887. attachments = attachments.rstrip(',').split(',')
  888. else:
  889. attachments = []
  890. note_id = api.new_note(session_id, title, content, attachments, viewers)
  891. return dumps({'redirect': '/note/%s' % note_id})
  892. elif action and action == 'last_changes':
  893. note = api.compare_with_previous_version(session_id, note_id, revision=0)
  894. mode = 'view'
  895. action = 'compare'
  896. title = 'Notes - Track changes'
  897. elif version is not None:
  898. app.logger.debug(version)
  899. note = api.get_note(session_id, note_id, version)
  900. mode = 'view'
  901. title = '%s v%s | Jupo Notes' % (note.title, version)
  902. elif request.path.endswith('/edit'):
  903. note = api.get_note(session_id, note_id)
  904. title = 'Notes - EditMode - %s' % note.title
  905. mode = 'edit'
  906. elif action == 'update':
  907. title = request.form.get('title', 'Untitled Note')
  908. content = request.form.get('content')
  909. viewers = request.form.get('viewers')
  910. if viewers:
  911. viewers = viewers.split(',')
  912. else:
  913. viewers = []
  914. attachments = request.form.get('attachments')
  915. app.logger.debug(attachments)
  916. if attachments:
  917. attachments = attachments.rstrip(',').split(',')
  918. else:
  919. attachments = []
  920. if note_id:
  921. api.update_note(session_id, note_id, title, content, attachments, viewers)
  922. else:
  923. note_id = api.new_note(session_id, title, content, attachments, viewers)
  924. return dumps({'redirect': '/note/%s' % note_id})
  925. elif action == 'remove':
  926. session_id = session.get("session_id")
  927. id = api.remove_note(session_id, note_id)
  928. return id
  929. elif action == 'mark_official':
  930. api.mark_official(session_id, note_id)
  931. return 'Done'
  932. elif action == 'mark_unofficial':
  933. api.mark_unofficial(session_id, note_id)
  934. return 'Done'
  935. elif action == 'mark_as_read':
  936. api.mark_as_read(session_id, note_id)
  937. return ':)'
  938. # elif action and action.startswith('restore_from_'):
  939. # revision = action.lstrip('restore_from_')
  940. # if revision.isdigit():
  941. # api.restore_note(session_id, note_id, int(revision))
  942. # note = api.get_note(session_id, note_id)
  943. # title = 'Notes - %s' % info.title
  944. # mode = 'view'
  945. # else:
  946. # pass #TODO: return an error page with code = 405
  947. elif action == 'comment':
  948. message = request.form.get('message')
  949. comment = api.new_comment(session_id, message, note_id)
  950. return render_template('comment.html',
  951. comment=comment,
  952. owner=owner,
  953. prefix='note')
  954. else:
  955. note = api.get_note(session_id, note_id)
  956. if not session_id and note is False:
  957. return redirect('/?back_to=%s' % request.path)
  958. if not note.id:
  959. abort(404)
  960. mode = 'view'
  961. recents = api.get_notes(session_id, limit=5)
  962. view = 'notes'
  963. if version is None and info:
  964. version = len(note.to_dict()['version'])
  965. group_id = request.args.get('group_id')
  966. if group_id:
  967. group = api.get_group_info(session_id, group_id)
  968. else:
  969. group = None
  970. if request.method in ["POST", "OPTIONS"]:
  971. body = render_template('notes.html',
  972. view='notes',
  973. mode=mode,
  974. action=action,
  975. version=version,
  976. recents=recents,
  977. note=note,
  978. group=group,
  979. owner=owner,
  980. content=content)
  981. info = {'body': body}
  982. if note:
  983. info['title'] = note.title
  984. else:
  985. info['title'] = 'Untitle Note'
  986. return Response(dumps(info), mimetype='application/json')
  987. else:
  988. return render_homepage(session_id, note.title,
  989. version=version,
  990. group=group, note=note, view='notes', mode='view')
  991. @app.route('/u<key>')
  992. @app.route('/u/<int:note_id>')
  993. def share_to_anyone_with_the_link(note_id=None, key=None):
  994. session_id = session.get("session_id")
  995. if key:
  996. doc = api.get_doc_by_key(key)
  997. return render_homepage(session_id, 'Note',
  998. view='discover', mode='view', doc=doc)
  999. else:
  1000. key = api.get_key(session_id, note_id)
  1001. if not key:
  1002. abort(404)
  1003. return redirect('/u' + key)
  1004. #===============================================================================
  1005. # Files
  1006. #===============================================================================
  1007. @app.route("/public/<path:filename>")
  1008. def public_files(filename):
  1009. filedata = cache.get('file:%s' % os.path.basename(filename)) \
  1010. if not settings.DEBUG else None
  1011. if not filedata:
  1012. path = os.path.join(os.path.dirname(__file__), 'public', filename)
  1013. if not os.path.exists(path):
  1014. abort(404, 'File not found')
  1015. filedata = open(path).read()
  1016. response = make_response(filedata)
  1017. response.headers['Content-Length'] = len(filedata)
  1018. response.headers['Content-Type'] = guess_type(filename)[0]
  1019. response.headers['Cache-Control'] = 'public'
  1020. response.headers['Expires'] = '31 December 2037 23:59:59 GMT'
  1021. return response
  1022. @app.route("/favicon.ico")
  1023. def favicon():
  1024. path = 'public/favicon.ico'
  1025. filedata = open(path).read()
  1026. response = make_response(filedata)
  1027. response.headers['Content-Length'] = len(filedata)
  1028. response.headers['Content-Type'] = 'image/x-icon'
  1029. return response
  1030. @app.route('/update_profile_picture', methods=['POST'])
  1031. @app.route('/user/<int:user_id>', methods=['GET', 'OPTIONS'])
  1032. @app.route('/user/<int:user_id>/page<int:page>', methods=['GET', 'OPTIONS'])
  1033. @app.route('/user/<int:user_id>/update', methods=['POST'])
  1034. @app.route('/user/<int:user_id>/complete_profile', methods=['POST'])
  1035. @app.route('/user/<int:user_id>/follow', methods=['POST'])
  1036. @app.route('/user/<int:user_id>/unfollow', methods=['POST'])
  1037. @app.route('/user/<int:user_id>/<view>', methods=['GET', 'OPTIONS'])
  1038. @login_required
  1039. @line_profile
  1040. def user(user_id=None, page=1, view=None):
  1041. session_id = session.get("session_id")
  1042. if request.path == '/update_profile_picture':
  1043. fid = request.args.get('fid')
  1044. api.update_user_info(session_id, {'avatar': long(fid)})
  1045. return 'OK'
  1046. owner = api.get_owner_info(session_id)
  1047. user = api.get_user_info(user_id)
  1048. if not user.id:
  1049. abort(404)
  1050. if view in ['edit', 'update_profile']:
  1051. resp = {'title': 'Update Profile',
  1052. 'body': render_template('user.html',
  1053. mode='edit',
  1054. view='update_profile',
  1055. owner=owner)}
  1056. return Response(dumps(resp), mimetype='application/json')
  1057. elif view == 'change_password':
  1058. resp = {'title': 'Change Password',
  1059. 'body': render_template('user.html',
  1060. mode='change_password',
  1061. owner=user)}
  1062. return Response(dumps(resp), mimetype='application/json')
  1063. elif request.path.endswith('/complete_profile'):
  1064. name = request.form.get('name')
  1065. gender = request.form.get('gender')
  1066. password = request.form.get('password')
  1067. avatar = request.files.get('file')
  1068. fid = api.new_attachment(session_id, avatar.filename, avatar.stream.read())
  1069. new_session_id = api.complete_profile(session_id,
  1070. name, password, gender, fid)
  1071. resp = redirect('/news_feed')
  1072. if new_session_id:
  1073. session['session_id'] = new_session_id
  1074. return resp
  1075. elif request.path.endswith('/update'):
  1076. old_password = request.form.get('current_password')
  1077. new_password = request.form.get('new_password')
  1078. confirm_new_password = request.form.get('confirm_new_password')
  1079. if old_password:
  1080. if new_password != confirm_new_password:
  1081. return redirect('/?message=New password does not match')
  1082. else:
  1083. ok = api.change_password(session_id, old_password, new_password)
  1084. api.set_status(session_id, 'offline')
  1085. api.sign_out(session_id)
  1086. session.pop('session_id')
  1087. return redirect('/?message=Password updated successfully.')
  1088. if not old_password and new_password and new_password == confirm_new_password:
  1089. if owner.has_password():
  1090. return redirect('/?message=Please enter your current password.')
  1091. else:
  1092. user_id = api.get_user_id(session_id)
  1093. api.reset_password(user_id, new_password)
  1094. return redirect('/?message=New password updated successfully.')
  1095. name = request.form.get('name')
  1096. gender = request.form.get('gender')
  1097. intro = request.form.get('intro')
  1098. location = request.form.get('location')
  1099. if location:
  1100. info = {'name': name,
  1101. 'gender': gender,
  1102. 'location': location,
  1103. 'introduction': intro}
  1104. else:
  1105. info = {'name': name,
  1106. 'gender': gender,
  1107. 'introduction': intro}
  1108. disabled_notifications = []
  1109. if not request.form.get('comments'):
  1110. disabled_notifications.append('comments')
  1111. if not request.form.get('share_posts'):
  1112. disabled_notifications.append('share_posts')
  1113. if not request.form.get('mentions'):
  1114. disabled_notifications.append('mentions')
  1115. info['disabled_notifications'] = disabled_notifications
  1116. birthday_day = request.form.get('birthday-day')
  1117. birthday_month = request.form.get('birthday-month')
  1118. birthday_year = request.form.get('birthday-year')
  1119. if birthday_day.isdigit() and birthday_month.isdigit() and birthday_year.isdigit():
  1120. info['birthday'] = '%s/%s/%s' % (birthday_day, birthday_month, birthday_year)
  1121. phone = request.form.get('phone')
  1122. if phone.replace('+', '').replace(' ', '').isdigit():
  1123. info['phone'] = phone
  1124. fid = request.form.get('fid')
  1125. if fid:
  1126. info['avatar'] = long(fid)
  1127. api.update_user_info(session_id, info)
  1128. return redirect('/news_feed')
  1129. elif request.path.endswith('/follow'):
  1130. api.add_to_contacts(session_id, user_id)
  1131. # api.follow(session_id, user_id)
  1132. return 'Done'
  1133. elif request.path.endswith('/unfollow'):
  1134. api.remove_from_contacts(session_id, user_id)
  1135. # api.unfollow(session_id, user_id)
  1136. return 'Done'
  1137. elif view == 'groups':
  1138. return dumps({'body': render_template('groups.html',
  1139. user=user,
  1140. owner=owner,
  1141. groups=user.groups)})
  1142. elif view == 'followers':
  1143. users = [api.get_user_info(user_id) for user_id in user.followers]
  1144. return dumps({'body': render_template('users.html',
  1145. title='Followers',
  1146. users=users)})
  1147. elif view == 'following':
  1148. users = [api.get_user_info(user_id) for user_id in user.following_users]
  1149. return dumps({'body': render_template('users.html',
  1150. title='Following',
  1151. users=users)})
  1152. elif view == 'starred':
  1153. posts = api.get_starred_posts(api.get_session_id(user_id))
  1154. body = render_template('user.html',
  1155. title='Starred',
  1156. category = 'starred',
  1157. view='user',
  1158. user=user,
  1159. owner=owner,
  1160. feeds=posts)
  1161. json = dumps({'body': body, 'title': 'Intelliview'})
  1162. return Response(json, mimetype='application/json')
  1163. else:
  1164. view = 'user'
  1165. title = user.name
  1166. if not session_id or owner.id == user.id:
  1167. feeds = api.get_public_posts(user_id=user.id, page=page)
  1168. else:
  1169. feeds = api.get_user_posts(session_id, user_id, page=page)
  1170. user.recent_files = api.get_user_files(session_id, user_id=user.id, limit=3)
  1171. user.recent_notes = api.get_user_notes(session_id, user_id=user.id, limit=3)
  1172. coworkers = [user]
  1173. if request.method == "OPTIONS":
  1174. if page == 1:
  1175. body = render_template('user.html',
  1176. view=view,
  1177. user=user,
  1178. owner=owner,
  1179. title=title,
  1180. coworkers=coworkers,
  1181. feeds=feeds)
  1182. json = dumps({"body": body,
  1183. "title": title})
  1184. return Response(json, mimetype='application/json')
  1185. else:
  1186. posts = [render(feeds, 'feed', owner, 'user')]
  1187. if len(feeds) == 0:
  1188. posts.append(render_template('more.html', more_url=None))
  1189. else:
  1190. posts.append(render_template('more.html',
  1191. more_url='/user/%s/page%d' \
  1192. % (user_id, page+1)))
  1193. return ''.join(posts)
  1194. else:
  1195. return render_homepage(session_id, title,
  1196. coworkers=coworkers,
  1197. user=user,
  1198. feeds=feeds, view=view)
  1199. @app.route("/contacts", methods=["GET", "OPTIONS"])
  1200. @login_required
  1201. def contacts():
  1202. session_id = session.get("session_id")
  1203. user_id = api.get_user_id(session_id)
  1204. owner = api.get_user_info(user_id)
  1205. body = render_template('contacts.html',
  1206. owner=owner)
  1207. return Response(dumps({'body': body,
  1208. 'title': 'Contacts'}),
  1209. mimetype='application/json')
  1210. @app.route("/networks", methods=['OPTIONS'])
  1211. @login_required
  1212. def networks():
  1213. session_id = session.get("session_id")
  1214. user_id = api.get_user_id(session_id)
  1215. if not user_id:
  1216. abort(400)
  1217. owner = api.get_user_info(user_id)
  1218. resp = {'body': render_template('networks.html', owner=owner),
  1219. 'title': 'Networks'}
  1220. return Response(dumps(resp), mimetype='application/json')
  1221. @app.route("/network/new", methods=['GET', 'POST'])
  1222. def network():
  1223. if request.path.endswith('/new'):
  1224. domain = subdomain = organization_name = msg = None
  1225. if request.method == 'POST':
  1226. domain = request.form.get('domain')
  1227. organization_name = request.form.get('name')
  1228. if domain:
  1229. if '.' not in domain:
  1230. msg = 'The domain you entered was invalid.'
  1231. elif not api.domain_is_ok(domain):
  1232. msg = '''\
  1233. Please make sure <strong>%s</strong> is mapped to <strong>play.jupo.com</strong>.<br>
  1234. If you already do it, please try again after few minutes. <br>
  1235. Normally it takes some time once you update your DNS records<br>
  1236. until the changes take effect around the world.''' % (domain)
  1237. subdomain = request.form.get('subdomain')
  1238. if subdomain and len(subdomain) > 50:
  1239. msg = 'Subdomain is too long.'
  1240. if subdomain and not api.domain_is_ok(subdomain + '.jupo.com'):
  1241. msg = 'Subdomain already exists.'
  1242. if not subdomain and not domain:
  1243. msg = 'Please enter a domain or choose a subdomain.'
  1244. if not organization_name:
  1245. msg = 'Please enter your organization name.'
  1246. if not msg:
  1247. # TODO: check subdomain is valid (a-Z0-9)
  1248. if subdomain:
  1249. db_name = subdomain.lower().strip() + '_jupo_com'
  1250. if api.is_exists(db_name=db_name):
  1251. msg = 'Subdomain already exists.'
  1252. elif domain:
  1253. db_name = domain.lower().strip().replace('.', '_')
  1254. if api.is_exists(db_name=db_name):
  1255. msg = 'Domain already exists.'
  1256. if db_name and not msg:
  1257. api.new_network(db_name, organization_name)
  1258. if subdomain:
  1259. return redirect('http://%s.jupo.com/sign_up?welcome=1' % subdomain)
  1260. else:
  1261. return redirect('http://%s/sign_up?welcome=1' % domain)
  1262. return render_template('new_network.html',
  1263. ip=api.PRIMARY_IP,
  1264. organization_name=organization_name,
  1265. domain=domain,
  1266. subdomain=subdomain,
  1267. message=msg)
  1268. @app.route("/everyone", methods=["GET", "OPTIONS"])
  1269. @app.route("/everyone/page<int:page>", methods=["GET", "OPTIONS"])
  1270. @app.route("/people", methods=["GET", "OPTIONS"])
  1271. @app.route("/groups", methods=["GET", "OPTIONS"])
  1272. @app.route("/group/new", methods=["GET", "OPTIONS", "POST"])
  1273. @app.route("/group/<int:group_id>/update", methods=["POST"])
  1274. @app.route("/group/<int:group_id>/follow", methods=["POST"])
  1275. @app.route("/group/<int:group_id>/unfollow", methods=["POST"])
  1276. @app.route("/group/<int:group_id>/highlight", methods=["POST"])
  1277. @app.route("/group/<int:group_id>/unhighlight", methods=["POST"])
  1278. @app.route("/group/<int:group_id>/add_member", methods=["POST"])
  1279. @app.route("/group/<int:group_id>/remove_member", methods=["POST"])
  1280. @app.route("/group/<int:group_id>/make_admin", methods=["POST"])
  1281. @app.route("/group/<int:group_id>/remove_as_admin", methods=["POST"])
  1282. @app.route("/group/<int:group_id>", methods=["GET", "OPTIONS"])
  1283. @app.route("/group/<int:group_id>/page<int:page>", methods=["OPTIONS"])
  1284. @app.route("/group/<int:group_id>/<view>", methods=["GET", "OPTIONS"])
  1285. @login_required
  1286. @line_profile
  1287. def group(group_id=None, view='group', page=1):
  1288. hostname = request.headers.get('Host')
  1289. session_id = session.get("session_id")
  1290. user_id = api.get_user_id(session_id)
  1291. if not user_id:
  1292. return redirect('/?continue=%s' % request.path)
  1293. owner = api.get_user_info(user_id)
  1294. hashtag = request.args.get('hashtag')
  1295. if request.path.startswith('/everyone'):
  1296. group_id = 'public'
  1297. if request.path == '/people':
  1298. group_id = 'public'
  1299. view = 'members'
  1300. if request.path.endswith('/new'):
  1301. if request.method == 'GET':
  1302. return render_homepage(session_id, 'Groups',
  1303. view='new-group')
  1304. name = request.form.get('name')
  1305. if name:
  1306. privacy = request.form.get('privacy', 'closed')
  1307. about = request.form.get('about')
  1308. members = set()
  1309. email_addrs = set()
  1310. for k in request.form.keys():
  1311. if k.startswith('member-'):
  1312. email = request.form.get(k).strip()
  1313. if email and email != owner.email:
  1314. email_addrs.add(email)
  1315. uid = api.get_user_id_from_email_address(email)
  1316. if uid:
  1317. members.add(uid)
  1318. group_id = api.new_group(session_id,
  1319. name, privacy, members,
  1320. about=about, email_addrs=email_addrs)
  1321. return str(group_id)
  1322. else:
  1323. body = render_template('new.html',
  1324. owner=owner,
  1325. view='new-group')
  1326. return Response(dumps({'title': 'New Group',
  1327. 'body': body}), mimetype='application/json')
  1328. if request.path.endswith('/follow'):
  1329. is_ok = api.join_group(session_id, group_id)
  1330. return 'Done'
  1331. elif request.path.endswith('/unfollow'):
  1332. api.leave_group(session_id, group_id)
  1333. return 'Done'
  1334. elif request.path.endswith('/highlight'):
  1335. note_id = request.args.get('note_id')
  1336. api.highlight(session_id, group_id, note_id)
  1337. return 'Done'
  1338. elif request.path.endswith('/unhighlight'):
  1339. note_id = request.args.get('note_id')
  1340. api.unhighlight(session_id, group_id, note_id)
  1341. return 'Done'
  1342. elif request.path.endswith('/add_member'):
  1343. user_id = request.args.get('user_id')
  1344. api.add_member(session_id, group_id, user_id)
  1345. return 'Done'
  1346. elif request.path.endswith('/remove_member'):
  1347. user_id = request.args.get('user_id')
  1348. api.remove_member(session_id, group_id, user_id)
  1349. return 'Done'
  1350. elif request.path.endswith('/make_admin'):
  1351. user_id = request.args.get('user_id')
  1352. api.make_admin(session_id, group_id, user_id)
  1353. return 'Done'
  1354. elif request.path.endswith('/remove_as_admin'):
  1355. user_id = request.args.get('user_id')
  1356. api.remove_as_admin(session_id, group_id, user_id)
  1357. return 'Done'
  1358. elif request.path.endswith('/update'):
  1359. name = request.form.get('name')
  1360. about = request.form.get('about')
  1361. privacy = request.form.get('privacy', 'closed')
  1362. post_permission = request.form.get('post_permission', 'members')
  1363. info = {'name': name,
  1364. 'privacy': privacy,
  1365. 'post_permission': post_permission,
  1366. 'about': about}
  1367. members = request.form.get('members')
  1368. if members:
  1369. members = [int(i) for i in members.split(',')]
  1370. else:
  1371. members = []
  1372. if members:
  1373. info['members'] = members
  1374. admins = request.form.get('administrators')
  1375. if admins:
  1376. admins = [int(i) for i in admins.split(',')]
  1377. else:
  1378. admins = []
  1379. if user_id not in admins:
  1380. admins.append(user_id)
  1381. if admins:
  1382. info['leaders'] = admins
  1383. fid = request.form.get('fid')
  1384. if fid:
  1385. info['avatar'] = long(fid)
  1386. api.update_group_info(session_id, group_id, info)
  1387. return redirect('/group/%s' % group_id)
  1388. if not group_id:
  1389. groups = api.get_groups(session_id)
  1390. featured_groups = api.get_featured_groups(session_id)
  1391. if request.method == 'GET':
  1392. return render_homepage(session_id, 'Groups',
  1393. groups=groups,
  1394. featured_groups=featured_groups,
  1395. view='groups')
  1396. else:
  1397. body = render_template('groups.html',
  1398. view='groups',
  1399. owner=owner,
  1400. featured_groups=featured_groups,
  1401. groups=groups)
  1402. resp = Response(dumps({'body': body,
  1403. 'title': 'Groups'}))
  1404. return resp
  1405. group = api.get_group_info(session_id, group_id)
  1406. if view == 'edit':
  1407. resp = {'title': 'Group Settings',
  1408. 'body': render_template('group.html',
  1409. hostname=hostname,
  1410. mode='edit',
  1411. group=group)}
  1412. return Response(dumps(resp), mimetype='application/json')
  1413. elif view == 'docs':
  1414. # group.docs = api.get_docs_count(group_id)
  1415. # group.files = api.get_files_count(group_id)
  1416. owner = api.get_owner_info(session_id)
  1417. docs = api.get_notes(session_id, group_id=group_id)
  1418. if request.method == 'OPTIONS':
  1419. body = render_template('group.html',
  1420. group=group,
  1421. owner=owner,
  1422. mode='docs',
  1423. docs=docs)
  1424. resp = Response(dumps({'body': body}), mimetype='application/json')
  1425. return resp
  1426. else:
  1427. return render_homepage(session_id, "%s's Notes" % group.name,
  1428. view='group',
  1429. mode='docs',
  1430. group=group,
  1431. docs=docs)
  1432. elif view == 'files':
  1433. abort(404)
  1434. elif view == 'events':
  1435. events = api.get_events(session_id, group_id, as_feeds=True)
  1436. body = render_template('events.html', events=events, owner=owner)
  1437. return dumps({'body': body, 'title': 'Events'})
  1438. elif view == 'members':
  1439. # app.logger.debug('aaaaaaAAAAAAAAAAAAAAA')
  1440. # group.docs = api.get_docs_count(group_id)
  1441. # group.files = api.get_files_count(group_id)
  1442. owner = api.get_owner_info(session_id)
  1443. # body = render_template('group.html',
  1444. # view='members',
  1445. # group=group, owner=owner)
  1446. # return dumps({'body': body})
  1447. body = render_template('members.html', group=group, owner=owner)
  1448. return Response(dumps({'body': body,
  1449. 'title': "%s's Members" % group.name}),
  1450. mimetype='application/json')
  1451. else:
  1452. if not group.id:
  1453. abort(404)
  1454. if group_id == 'public':
  1455. feeds = api.get_public_posts(session_id, page=page)
  1456. else:
  1457. feeds = api.get_feeds(session_id, group_id, page=page)
  1458. api.add_to_recently_viewed_list(session_id, group_id)
  1459. if not group.highlight_ids:
  1460. group.recent_notes = api.get_notes(session_id, group_id=group_id, limit=3)
  1461. group.recent_files = api.get_attachments(session_id,
  1462. group_id=group_id, limit=3)
  1463. owner = api.get_owner_info(session_id)
  1464. if request.method == 'OPTIONS':
  1465. if page > 1:
  1466. posts = [render(feeds, "feed", owner, view)]
  1467. if len(feeds) == 0:
  1468. posts.append(render_template('more.html', more_url=None))
  1469. elif group_id == 'public':
  1470. posts.append(render_template('more.html',
  1471. more_url='/everyone/page%d' % (page+1)))
  1472. else:
  1473. posts.append(render_template('more.html',
  1474. more_url='/group/%s/page%d' \
  1475. % (group_id, page+1)))
  1476. return ''.join(posts)
  1477. else:
  1478. # upcoming_events = api.get_upcoming_events(session_id, group_id)
  1479. resp = {'title': group.name,
  1480. 'body': render_template('group.html',
  1481. feeds=feeds,
  1482. group=group,
  1483. owner=owner,
  1484. # upcoming_events=upcoming_events,
  1485. view=view)}
  1486. json = dumps(resp)
  1487. resp = Response(json, mimetype='application/json')
  1488. return resp
  1489. else:
  1490. stats = {}
  1491. groups = api.get_groups(session_id)
  1492. # upcoming_events = api.get_upcoming_events(session_id, group_id)
  1493. resp = render_homepage(session_id,
  1494. group.name,
  1495. feeds=feeds,
  1496. view=view,
  1497. group=group,
  1498. # upcoming_events=upcoming_events,
  1499. )
  1500. # resp.set_cookie('last_g%s' % group_id, api.utctime())
  1501. return resp
  1502. @app.route('/chat/user/<int:user_id>', methods=['GET', 'OPTIONS'])
  1503. @app.route('/chat/user/<int:user_id>/<action>', methods=['POST'])
  1504. @app.route('/chat/topic/<int:topic_id>', methods=['GET', 'OPTIONS'])
  1505. @app.route('/chat/topic/<int:topic_id>/<action>', methods=['POST'])
  1506. @login_required
  1507. def chat(topic_id=None, user_id=None, action=None):
  1508. session_id = session.get("session_id")
  1509. if action == 'new_message':
  1510. msg = request.form.get('message')
  1511. html = api.new_message(session_id, msg,
  1512. user_id=user_id, topic_id=topic_id)
  1513. return html
  1514. elif action == 'new_file':
  1515. file = request.files.get('file')
  1516. filename = file.filename
  1517. attachment_id = api.new_attachment(session_id,
  1518. file.filename,
  1519. file.stream.read())
  1520. html = api.new_message(session_id, attachment_id,
  1521. user_id=user_id, topic_id=topic_id)
  1522. return html
  1523. elif action == 'mark_as_read':
  1524. owner_id = api.get_user_id(session_id)
  1525. if user_id:
  1526. api.update_last_viewed(owner_id, user_id=user_id)
  1527. else:
  1528. api.update_last_viewed(owner_id, topic_id=topic_id)
  1529. return 'OK'
  1530. else:
  1531. owner_id = api.get_user_id(session_id)
  1532. user = topic = seen_by = None
  1533. if user_id:
  1534. user = api.get_user_info(user_id)
  1535. last_viewed = api.get_last_viewed(user_id, owner_id) \
  1536. + int(api.get_utcoffset(owner_id))
  1537. last_viewed_friendly_format = api.friendly_format(last_viewed, short=True)
  1538. if last_viewed_friendly_format.startswith('Today'):
  1539. last_viewed_friendly_format = last_viewed_friendly_format.split(' at ')[-1]
  1540. messages = api.get_chat_history(session_id, user_id)
  1541. if messages and (messages[-1].sender.id == owner_id) and (messages[-1].timestamp < last_viewed):
  1542. seen_by = 'Seen %s' % last_viewed_friendly_format
  1543. else:
  1544. last_viewed = last_viewed_friendly_format = 0
  1545. topic = api.get_topic_info(topic_id)
  1546. messages = api.get_chat_history(session_id, topic_id=topic_id)
  1547. if messages:
  1548. utcoffset = int(api.get_utcoffset(owner_id))
  1549. last_viewed = {}
  1550. seen_by = []
  1551. for i in topic.member_ids:
  1552. ts = api.get_last_viewed(i, topic_id=topic_id) + utcoffset
  1553. last_viewed[i] = ts
  1554. if messages[-1].timestamp < ts:
  1555. seen_by.append(i)
  1556. app.logger.debug(seen_by)
  1557. app.logger.debug(last_viewed)
  1558. app.logger.debug(messages[-1].timestamp)
  1559. if seen_by:
  1560. if len(seen_by) >= len(topic.member_ids):
  1561. seen_by = 'Seen by everyone.'
  1562. else:
  1563. seen_by = 'Seen by %s' % ', '.join([api.get_user_info(i).name for i in seen_by])
  1564. return render_template('chat.html',
  1565. owner={'id': owner_id},
  1566. seen_by=seen_by,
  1567. messages=messages, user=user, topic=topic)
  1568. @app.route("/messages", methods=['GET', 'OPTIONS'])
  1569. @login_required
  1570. @line_profile
  1571. def messages():
  1572. session_id = session.get("session_id")
  1573. user_id = api.get_user_id(session_id)
  1574. owner = api.get_user_info(user_id)
  1575. suggested_friends = api.get_friend_suggestions(owner.to_dict())
  1576. coworkers = api.get_coworkers(session_id)
  1577. messages = api.get_messages(session_id)
  1578. if request.method == 'GET':
  1579. return render_homepage(session_id, 'Messages',
  1580. suggested_friends=suggested_friends,
  1581. coworkers=coworkers,
  1582. messages=messages,
  1583. view='messages')
  1584. else:
  1585. body = render_template('messages.html',
  1586. suggested_friends=suggested_friends,
  1587. coworkers=coworkers,
  1588. messages=messages,
  1589. owner=owner)
  1590. resp = Response(dumps({'body': body,
  1591. 'title': 'Messages'}))
  1592. return resp
  1593. @app.route("/", methods=["GET"])
  1594. def home():
  1595. hostname = request.headers.get('Host', '').split(':')[0]
  1596. session_id = request.args.get('session_id')
  1597. if hostname != settings.PRIMARY_DOMAIN:
  1598. if not api.is_exists(db_name=hostname.replace('.', '_')):
  1599. abort(404)
  1600. if session_id:
  1601. session.permanent = True
  1602. session['session_id'] = request.args.get('session_id')
  1603. return redirect('/news_feed')
  1604. session_id = session.get("session_id")
  1605. user_id = api.get_user_id(session_id)
  1606. if not user_id:
  1607. code = request.args.get('code')
  1608. user_id = api.get_user_id(code)
  1609. if user_id and not session_id:
  1610. session['session_id'] = code
  1611. owner = api.get_user_info(user_id)
  1612. return render_template('profile_setup.html',
  1613. owner=owner,
  1614. code=code, user_id=user_id)
  1615. if not session_id or not user_id:
  1616. try:
  1617. session.pop('session_id')
  1618. except KeyError:
  1619. pass
  1620. if hostname != settings.PRIMARY_DOMAIN:
  1621. return redirect('/sign_in')
  1622. new_user = request.cookies.get('new_user', "1")
  1623. email = request.args.get('email')
  1624. message = request.args.get('message')
  1625. resp = Response(render_template('landing_page.html',
  1626. email=email,
  1627. message=message,
  1628. new_user=new_user))
  1629. back_to = request.args.get('back_to')
  1630. if back_to:
  1631. resp.set_cookie('redirect_to', back_to)
  1632. return resp
  1633. else:
  1634. return redirect('/news_feed')
  1635. @app.route("/news_feed", methods=["GET", "OPTIONS"])
  1636. @app.route("/news_feed/page<int:page>", methods=["GET", "OPTIONS"])
  1637. @app.route('/archived', methods=['GET', 'OPTIONS'])
  1638. @app.route('/archived/page<int:page>', methods=['GET', 'OPTIONS'])
  1639. @app.route("/news_feed/archive_from_here", methods=["POST"])
  1640. @login_required
  1641. @line_profile
  1642. def news_feed(page=1):
  1643. session_id = session.get("session_id")
  1644. if request.path.endswith('archive_from_here'):
  1645. ts = float(request.args.get('ts', api.utctime()))
  1646. api.archive_posts(session_id, ts)
  1647. return 'Done'
  1648. user_id = api.get_user_id(session_id)
  1649. if user_id and request.cookies.get('redirect_to'):
  1650. redirect_to = request.cookies.get('redirect_to')
  1651. if redirect_to != request.url:
  1652. resp = redirect(request.cookies.get('redirect_to'))
  1653. resp.delete_cookie('redirect_to')
  1654. return resp
  1655. # Bắt user dùng facebook phải invite friends trước khi dùng ứng dụng
  1656. #
  1657. # if request.args.get('request') and request.args.get('to[0]'):
  1658. # api.update_user_info(session_id, {'fb_request_sent': True})
  1659. #
  1660. # else:
  1661. # user = api.get_user_info(user_id)
  1662. # if not user.fb_request_sent:
  1663. # return redirect('https://www.facebook.com/dialog/apprequests?app_id=%s' % settings.FACEBOOK_APP_ID \
  1664. # + '&message=Qua%20%C4%91%C3%A2y%20th%E1%BB%AD%20c%C3%A1i%20n%C3%A0o%20:-)&redirect_uri=https://www.jupo.com/')
  1665. #
  1666. #####
  1667. filter = request.args.get('filter', 'default')
  1668. app.logger.debug('session_id: %s' % session_id)
  1669. view = 'news_feed'
  1670. title = "Jupo"
  1671. if filter == 'archived':
  1672. feeds = api.get_archived_posts(session_id, page=page)
  1673. category = 'archived'
  1674. elif filter == 'email':
  1675. feeds = api.get_emails(session_id, page=page)
  1676. category = 'email'
  1677. elif filter == 'all':
  1678. feeds = api.get_feeds(session_id, page=page,
  1679. include_archived_posts=True)
  1680. category = None
  1681. # elif '@' in filter:
  1682. # feeds = api.get_emails(session_id, page)
  1683. else:
  1684. feeds = api.get_feeds(session_id, page=page,
  1685. include_archived_posts=False)
  1686. category = None
  1687. owner = api.get_user_info(user_id)
  1688. if request.method == "OPTIONS":
  1689. if page > 1:
  1690. posts = []
  1691. for feed in feeds:
  1692. if feed.id not in owner.unfollow_posts:
  1693. posts.append(render(feed, "feed", owner, view))
  1694. if len(feeds) == 0:
  1695. posts.append(render_template('more.html', more_url=None))
  1696. elif filter:
  1697. posts.append(render_template('more.html',
  1698. more_url='/news_feed/page%d?filter=%s' \
  1699. % (page+1, filter)))
  1700. else:
  1701. posts.append(render_template('more.html',
  1702. more_url='/news_feed/page%d' % (page+1)))
  1703. return ''.join(posts)
  1704. else:
  1705. pinned_posts = api.get_pinned_posts(session_id) \
  1706. if filter == 'default' else None
  1707. suggested_friends = api.get_friend_suggestions(owner.to_dict())
  1708. coworkers = api.get_coworkers(session_id)
  1709. browser = api.Browser(request.headers.get('User-Agent'))
  1710. body = render_template('news_feed.html',
  1711. owner=owner,
  1712. view=view,
  1713. title=title,
  1714. filter=filter,
  1715. browser=browser,
  1716. category=category,
  1717. coworkers=coworkers,
  1718. suggested_friends=suggested_friends,
  1719. pinned_posts=pinned_posts,
  1720. feeds=feeds)
  1721. json = dumps({"body": body,
  1722. "title": title})
  1723. resp = Response(json, mimetype='application/json')
  1724. else:
  1725. pinned_posts = api.get_pinned_posts(session_id) \
  1726. if filter == 'default' else None
  1727. suggested_friends = api.get_friend_suggestions(owner.to_dict())
  1728. coworkers = api.get_coworkers(user_id, limit=5)
  1729. browser = api.Browser(request.headers.get('User-Agent'))
  1730. resp = render_homepage(session_id, title,
  1731. view=view,
  1732. coworkers=coworkers,
  1733. filter=filter,
  1734. browser=browser,
  1735. category=category,
  1736. pinned_posts=pinned_posts,
  1737. suggested_friends=suggested_friends,
  1738. feeds=feeds)
  1739. resp.set_cookie('new_user', "0")
  1740. resp.delete_cookie('redirect_to')
  1741. return resp
  1742. @app.route("/feed/new", methods=['POST'])
  1743. @app.route("/feed/<int:feed_id>", methods=['GET', 'OPTIONS'])
  1744. @app.route("/post/<int:feed_id>", methods=['GET'])
  1745. @app.route("/feed/<int:feed_id>/<action>", methods=["POST"])
  1746. @app.route("/feed/<int:feed_id>/<int:comment_id>/<action>", methods=["POST"])
  1747. @app.route("/feed/<int:feed_id>/starred", methods=["OPTIONS"])
  1748. @app.route("/feed/<int:feed_id>/<message_id>@<domain>", methods=["GET", "OPTIONS"])
  1749. @app.route("/feed/<int:feed_id>/comments", methods=["OPTIONS"])
  1750. @app.route("/feed/<int:feed_id>/viewers", methods=["GET", "POST"])
  1751. @app.route("/feed/<int:feed_id>/reshare", methods=["GET", "POST"])
  1752. @line_profile
  1753. def feed_actions(feed_id=None, action=None,
  1754. message_id=None, domain=None, comment_id=None):
  1755. session_id = session.get("session_id")
  1756. # if message_id:
  1757. # message_id = '%s@%s' % (message_id, domain)
  1758. #
  1759. # # TODO: check permission
  1760. # message = api.DATABASE[api.get_database_name(request)].stream.find_one({'message_id': message_id})
  1761. # if not message:
  1762. # thread = api.DATABASE.stream.find_one({'comments.message_id': message_id})
  1763. # if thread:
  1764. # comments = thread['comments']
  1765. # for comment in comments:
  1766. # if comment.get('message_id') == message_id:
  1767. # message = comment
  1768. # message['subject'] = thread['subject']
  1769. # message['body'] = comment.get('html', comment.get('message'))
  1770. # break
  1771. # else:
  1772. # abort(404)
  1773. # else:
  1774. # message['body'] = message.get('html', message.get('body'))
  1775. #
  1776. #
  1777. # if request.method == 'OPTIONS':
  1778. # message['id'] = feed_id
  1779. # return dumps({'body': render_template('email.html', feed=message),
  1780. # 'title': message['subject']})
  1781. # return message
  1782. # else:
  1783. # return render_homepage(session_id, message['subject'],
  1784. # view='email', mode='view', feed=message)
  1785. owner = api.get_owner_info(session_id)
  1786. # if not owner.id:
  1787. # return redirect('/sign_in?continue=%s' % request.path)
  1788. if request.path.endswith('new'):
  1789. facebook_access_token = session.get('facebook_access_token', [None])[0]
  1790. message = request.form.get('message')
  1791. viewers = request.form.get('viewers')
  1792. if viewers:
  1793. viewers = viewers.split(',')
  1794. else:
  1795. viewers = []
  1796. attachments = request.form.get('attachments')
  1797. if attachments:
  1798. attachments = attachments.rstrip(',').split(',')
  1799. attachments = list(set(attachments))
  1800. else:
  1801. attachments = []
  1802. feed_id = api.new_feed(session_id,
  1803. message,
  1804. viewers,
  1805. attachments,
  1806. facebook_access_token=facebook_access_token)
  1807. feed = api.get_feed(session_id, feed_id)
  1808. return render_template('feed.html',
  1809. view=request.args.get('rel'),
  1810. feed=feed, owner=owner, hide_comments=True)
  1811. elif request.path.endswith('/viewers'):
  1812. if request.method == 'GET':
  1813. feed = api.get_feed(session_id, feed_id)
  1814. return render_template('viewers.html', feed=feed)
  1815. else:
  1816. viewers = request.form.get('viewers')
  1817. viewers = viewers.split(',')
  1818. api.set_viewers(session_id, feed_id, viewers)
  1819. feed = api.get_feed(session_id, feed_id)
  1820. return render_template('feed.html',
  1821. owner=owner,
  1822. feed=feed)
  1823. elif request.path.endswith('/reshare'):
  1824. if request.method == 'GET':
  1825. return render_template('reshare.html', feed_id=feed_id)
  1826. else:
  1827. viewers = request.form.get('to')
  1828. viewers = viewers.split(',')
  1829. app.logger.debug(viewers)
  1830. api.reshare(session_id, feed_id, viewers)
  1831. feed = api.get_feed(session_id, feed_id)
  1832. return render_template('feed.html',
  1833. view='discover',
  1834. owner=owner,
  1835. feed=feed)
  1836. elif request.path.endswith('/starred'):
  1837. feed = api.get_feed(session_id, feed_id)
  1838. users = feed.starred_by
  1839. body = render_template('users.html', title='Starred', users=users)
  1840. json = dumps({'body': body, 'title': 'Intelliview'})
  1841. return Response(json, mimetype='application/json')
  1842. elif request.path.endswith('/comments'):
  1843. limit = int(request.args.get('limit', 5))
  1844. last_comment_id = int(request.args.get('last'))
  1845. post = api.get_feed(session_id, feed_id)
  1846. if not post.id:
  1847. abort(400)
  1848. comments = []
  1849. for comment in post.comments:
  1850. if comment.id == last_comment_id:
  1851. break
  1852. else:
  1853. comments.append(comment)
  1854. if len(comments) > limit:
  1855. comments = comments[-limit:]
  1856. html = render(comments, 'comment',
  1857. owner, None, None,
  1858. item=post, hidden=True)
  1859. resp = {'html': html,
  1860. 'length': len(comments),
  1861. 'comments_count': post.comments_count}
  1862. if comments[0].id != post.comments[0].id:
  1863. resp['next_url'] = '/feed/%s/comments?last=%s' \
  1864. % (feed_id, comments[0].id)
  1865. return Response(dumps(resp), mimetype='application/json')
  1866. elif action == 'remove':
  1867. group_id = request.args.get('group_id')
  1868. api.remove_feed(session_id, feed_id, group_id=group_id)
  1869. elif action == 'undo_remove':
  1870. feed_id = api.undo_remove(session_id, feed_id)
  1871. elif action == 'star':
  1872. feed_id = api.star(session_id, feed_id)
  1873. elif action == 'unstar':
  1874. feed_id = api.unstar(session_id, feed_id)
  1875. elif action == 'pin':
  1876. feed_id = api.pin(session_id, feed_id)
  1877. elif action == 'unpin':
  1878. feed_id = api.unpin(session_id, feed_id)
  1879. elif action == 'archive':
  1880. api.archive_post(session_id, feed_id)
  1881. elif action == 'unarchive':
  1882. api.unarchive_post(session_id, feed_id)
  1883. elif action == 'remove_comment':
  1884. api.remove_comment(session_id, comment_id, post_id=feed_id)
  1885. elif action == 'update_comment':
  1886. message = request.form.get('message')
  1887. api.update_comment(session_id, comment_id, message, post_id=feed_id)
  1888. comment = '''{{ message | autolink | autoemoticon | nl2br | sanitize }}'''
  1889. message = api.filters.sanitize_html(\
  1890. api.filters.nl2br(\
  1891. api.filters.autoemoticon(\
  1892. api.filters.autolink(message))))
  1893. return message
  1894. elif action == 'unfollow':
  1895. feed_id = api.unfollow_post(session_id, feed_id)
  1896. elif action == 'mark_as_task':
  1897. api.mark_as_task(session_id, feed_id)
  1898. elif action == 'mark_unresolved':
  1899. api.mark_unresolved(session_id, feed_id)
  1900. elif action == 'mark_as_read':
  1901. api.mark_as_read(session_id, feed_id)
  1902. elif action == 'comment':
  1903. message = request.form.get('message', '')
  1904. attachments = request.form.get('attachments')
  1905. reply_to = request.form.get('reply_to')
  1906. if reply_to.isdigit():
  1907. reply_to = int(reply_to)
  1908. else:
  1909. reply_to = None
  1910. from_addr = request.form.get('from')
  1911. app.logger.debug(from_addr)
  1912. if not message and not attachments:
  1913. abort(403)
  1914. app.logger.debug(attachments)
  1915. if attachments:
  1916. attachments = attachments.rstrip(',').split(',')
  1917. attachments = list(set(attachments))
  1918. else:
  1919. attachments = []
  1920. info = api.new_comment(session_id,
  1921. message, feed_id, attachments,
  1922. reply_to=reply_to,
  1923. from_addr=from_addr)
  1924. if not info:
  1925. abort(400)
  1926. item = {'id': feed_id}
  1927. html = render_template('comment.html',
  1928. comment=info,
  1929. prefix='feed',
  1930. item=item,
  1931. owner=owner)
  1932. return html
  1933. else:
  1934. feed = api.get_feed(session_id, feed_id)
  1935. if request.method == 'OPTIONS':
  1936. body = render_template('news_feed.html',
  1937. view='news_feed',
  1938. mode='view',
  1939. owner=owner,
  1940. feed=feed)
  1941. msg = filters.clean(feed.message)
  1942. if not msg or \
  1943. (msg and str(msg).strip()[0] == '{' and str(msg).strip()[-1] == '}'):
  1944. title = ''
  1945. else:
  1946. title = msg if len(msg)<= 50 else msg[:50] + '...'
  1947. title = title.decode('utf-8', 'ignore').encode('utf-8')
  1948. json = dumps({'body': body, 'title': title})
  1949. return Response(json, mimetype='application/json')
  1950. else:
  1951. if not session_id and feed is False:
  1952. return redirect('/?back_to=%s' % request.path)
  1953. if session_id and not feed.id:
  1954. abort(404)
  1955. image = description = None
  1956. if feed.is_note():
  1957. title = feed.details.title
  1958. description = feed.details.content
  1959. # TODO: insert image of post
  1960. elif feed.is_file():
  1961. title = feed.details.name
  1962. description = feed.details.size
  1963. else:
  1964. msg = filters.clean(feed.message)
  1965. if not msg or \
  1966. (msg and str(msg).strip()[0] == '{' and str(msg).strip()[-1] == '}'):
  1967. title = ''
  1968. else:
  1969. title = msg if len(msg)<= 50 else msg[:50] + '...'
  1970. title = title.decode('utf-8', 'ignore').encode('utf-8')
  1971. if feed.urls:
  1972. url = feed.urls[0]
  1973. description = feed.urls[0].description
  1974. if url.img_src:
  1975. image = url.img_src
  1976. else:
  1977. image = url.favicon
  1978. if request.path.startswith('/post/') or not owner.id:
  1979. return render_template('post.html',
  1980. background='dark-bg',
  1981. owner=owner,
  1982. mode='view',
  1983. title=title, description=description, image=image, feed=feed)
  1984. else:
  1985. return render_homepage(session_id,
  1986. title=title, description=description, image=image,
  1987. view='feed', mode='view', feed=feed)
  1988. return str(feed_id)
  1989. @csrf.exempt
  1990. @app.route('/hooks/<service>/<key>', methods=['POST'])
  1991. @app.route('/group/<int:group_id>/new_<service>_key')
  1992. def service_hooks(service, key=None, group_id=None):
  1993. hostname = request.headers.get('Host')
  1994. if group_id: # new key
  1995. session_id = session.get('session_id')
  1996. key = api.get_new_webhook_key(session_id, group_id, service)
  1997. return 'http://%s/hooks/%s/%s' % (hostname, service, key)
  1998. if service == 'gitlab':
  1999. feed_id = api.new_hook_post(service, key, request.data)
  2000. elif service == 'github':
  2001. feed_id = api.new_hook_post(service, key, request.form.get('payload'))
  2002. return str(feed_id)
  2003. @app.route('/events', methods=['GET', 'OPTIONS'])
  2004. def events():
  2005. session_id = session.get("session_id")
  2006. events = api.get_events(session_id, as_feeds=True)
  2007. if request.method == 'GET':
  2008. return render_homepage(session_id, 'Events',
  2009. view='events',
  2010. events=events)
  2011. else:
  2012. owner = api.get_owner_info(session_id)
  2013. body = render_template('events.html', events=events, owner=owner)
  2014. return dumps({'body': body, 'title': 'Events'})
  2015. @app.route('/event/new', methods=['OPTIONS', 'POST'])
  2016. @app.route('/event/<int:event_id>', methods=['GET', 'OPTIONS'])
  2017. @app.route('/event/<int:event_id>/mark_as_read', methods=['GET', 'POST'])
  2018. @app.route('/<int:group_id>/events', methods=['GET', 'POST'])
  2019. def event(event_id=None, group_id=None):
  2020. session_id = session.get("session_id")
  2021. if request.path == '/event/new':
  2022. group_id = request.args.get('group_id')
  2023. name = request.form.get("name")
  2024. if not name: # not submit
  2025. if group_id:
  2026. group = api.get_group_info(session_id, group_id)
  2027. else:
  2028. group = None
  2029. body = render_template('event.html', group=group)
  2030. return dumps({'body': body})
  2031. when = request.form.get('when')
  2032. when = strptime(when, "%a %d, %B %Y - %I:%M%p")
  2033. when = mktime(when)
  2034. where = request.form.get('where')
  2035. details = request.form.get('details')
  2036. viewers = request.form.get('viewers')
  2037. if viewers:
  2038. viewers = viewers.split(',')
  2039. event_id = api.new_event(session_id, name, when, where, None, details, viewers)
  2040. event = api.get_event(session_id, event_id)
  2041. body = render_template('event.html',
  2042. event=event)
  2043. return dumps({'body': body,
  2044. 'reload': True})
  2045. elif group_id:
  2046. events = api.get_events(session_id, group_id)
  2047. pass
  2048. elif event_id:
  2049. if request.path.endswith('mark_as_read'):
  2050. api.mark_as_read(session_id, event_id)
  2051. return 'Done'
  2052. event = api.get_event(session_id, event_id)
  2053. body = render_template('event.html', event=event)
  2054. return dumps({'body': body})
  2055. else:
  2056. event = api.get_events(session_id)
  2057. @app.route("/files", methods=['GET', 'OPTIONS'])
  2058. @login_required
  2059. @line_profile
  2060. def files():
  2061. session_id = session.get("session_id")
  2062. owner = api.get_owner_info(session_id)
  2063. title = "Files"
  2064. files = api.get_files(session_id)
  2065. attachments = api.get_attachments(session_id)
  2066. if request.method == 'OPTIONS':
  2067. body = render_template('files.html',
  2068. view='files',
  2069. owner=owner,
  2070. files=files,
  2071. attachments=attachments)
  2072. return dumps({'body': body,
  2073. 'title': 'Files'})
  2074. else:
  2075. return render_homepage(session_id, title,
  2076. view='files',
  2077. files=files,
  2078. attachments=attachments)
  2079. @app.route("/attachment/new", methods=["POST"])
  2080. @app.route("/attachment/<int:attachment_id>")
  2081. @app.route("/attachment/<int:attachment_id>.png")
  2082. @app.route("/attachment/<int:attachment_id>.jpg")
  2083. @app.route("/attachment/<int:attachment_id>/<action>", methods=["POST"])
  2084. def attachment(attachment_id=None, action=None):
  2085. session_id = session.get("session_id")
  2086. if request.path.endswith('new'):
  2087. file = request.files.get('file')
  2088. filename = file.filename
  2089. attachment_id = api.new_attachment(session_id,
  2090. file.filename,
  2091. file.stream.read())
  2092. info = api.get_attachment_info(attachment_id)
  2093. info = {'html': render_template('attachment.html', attachment=info),
  2094. 'attachment_id': str(attachment_id)}
  2095. json = dumps(info)
  2096. return Response(json, mimetype='application/json')
  2097. elif action == 'remove':
  2098. api.remove_attachment(session_id, attachment_id)
  2099. return str(attachment_id)
  2100. else:
  2101. attachment = api.get_attachment(attachment_id)
  2102. post_id = request.args.get('rel')
  2103. viewers = []
  2104. if post_id:
  2105. post = api.get_feed(session_id, int(post_id))
  2106. if (post and not post.id) or not post:
  2107. abort(400)
  2108. comments = post.to_dict().get('comments')
  2109. if attachment_id in post.attachment_ids:
  2110. viewers = post.viewer_ids
  2111. elif comments:
  2112. for comment in comments:
  2113. if attachment_id in comment.get('attachments', []):
  2114. viewers = post.viewer_ids
  2115. break
  2116. else:
  2117. abort(403, 'Permission Denied')
  2118. else:
  2119. viewers = [api.get_attachment_info(attachment_id).owner.id]
  2120. if isinstance(attachment, unicode) or isinstance(attachment, str):
  2121. s3_url = attachment
  2122. return redirect(s3_url, code=301)
  2123. if not attachment:
  2124. abort(404, 'File not found')
  2125. filedata = attachment.read()
  2126. filename = attachment._filename
  2127. resp = Response(filedata)
  2128. name = request.args.get('name', request.args.get('filename'))
  2129. content_type = attachment.content_type \
  2130. if attachment.content_type \
  2131. else 'application/octet-stream'
  2132. if not name and not content_type.startswith('image/'):
  2133. name = filename
  2134. if name:
  2135. resp.headers['Content-Disposition'] = str('attachment; filename="%s"' % name)
  2136. resp.headers['Content-Type'] = guess_type(name)[0]
  2137. else:
  2138. resp.headers['Content-Type'] = guess_type(filename)[0]
  2139. return resp
  2140. @app.route("/img/<int:attachment_id>.png")
  2141. @app.route("/img/<int:attachment_id>.jpg")
  2142. @app.route("/img/<size>/<int:attachment_id>.png")
  2143. @app.route("/img/<size>/<int:attachment_id>.jpg")
  2144. def profile_pictures(attachment_id, size='60'):
  2145. try:
  2146. info = api.get_attachment_info(attachment_id)
  2147. if info.md5 and api.is_s3_file(info.md5 + '_%s.jpg' % size):
  2148. url = 'https://%s.s3.amazonaws.com/%s_%s.jpg' % (settings.S3_BUCKET_NAME, info.md5, size)
  2149. return redirect(url, code=301)
  2150. data = api.get_file_data(attachment_id)
  2151. if not data:
  2152. return redirect('http://www.jupo.com/public/images/avatar.96.gif')
  2153. if size.isdigit():
  2154. size = int(size)
  2155. filedata = zoom(data, size, size)
  2156. else:
  2157. width, height = size.split('_')
  2158. filedata = zoom(data, int(width), int(height))
  2159. domain = request.headers.get('Host')
  2160. db_name = domain.lower().strip().replace('.', '_')
  2161. api.move_to_s3_queue.enqueue(api.move_to_s3, '%s_%s.jpg|%s|%s' \
  2162. % (api.hashlib.md5(data).hexdigest(),
  2163. str(size), 'image/jpeg', filedata),
  2164. db_name)
  2165. return Response(filedata, mimetype='image/jpeg')
  2166. except api.NoFile: # 'NoneType' object has no attribute 'get'
  2167. return redirect('http://www.jupo.com/public/images/avatar.96.gif')
  2168. # abort(404, 'File not found')
  2169. @app.route("/file/new", methods=["POST"])
  2170. @app.route("/file/<int:file_id>", methods=["GET", "POST", "OPTIONS"])
  2171. @app.route("/file/<int:file_id>/<action>", methods=["POST"])
  2172. def file(file_id=None, action=None, size=None):
  2173. session_id = session.get("session_id")
  2174. owner = api.get_owner_info(session_id)
  2175. if request.path == '/file/new':
  2176. attachments = request.form.get('attachments')
  2177. attachments = [i for i in attachments.split(',') if i]
  2178. viewers = request.form.get('viewers')
  2179. if viewers:
  2180. viewers = viewers.split(',')
  2181. else:
  2182. viewers = []
  2183. blocks = []
  2184. for attachment in attachments:
  2185. file_id = api.new_file(session_id, attachment, viewers)
  2186. file = api.get_file_info(session_id, file_id)
  2187. blocks.append(render_template('file.html',
  2188. owner=owner,
  2189. file=file))
  2190. return ''.join(blocks)
  2191. elif action == 'mark_as_read':
  2192. api.mark_as_read(session_id, file_id)
  2193. return 'Done'
  2194. elif action == 'comment':
  2195. message = request.form.get('message')
  2196. info = api.new_comment(session_id, message, file_id)
  2197. return render_template('comment.html',
  2198. comment=info,
  2199. prefix='stream',
  2200. owner=owner)
  2201. elif action == 'update':
  2202. file = request.files.get('file')
  2203. filename = file.filename
  2204. attachment_id = api.new_attachment(session_id,
  2205. file.filename,
  2206. file.stream.read())
  2207. api.update_file(session_id, file_id, attachment_id)
  2208. info = api.get_file_info(session_id, file_id)
  2209. info = {'html': render_template('file.html',
  2210. owner=owner,
  2211. file=info)}
  2212. return Response(dumps(info), mimetype='application/json')
  2213. elif action == 'rename':
  2214. new_name = request.form.get('name')
  2215. if not new_name:
  2216. abort(400)
  2217. api.rename_file(session_id, file_id, new_name)
  2218. info = api.get_file_info(session_id, file_id)
  2219. return render_template('file.html', owner=owner,file=info)
  2220. else:
  2221. file = api.get_file_info(session_id, file_id)
  2222. body = render_template('files.html',
  2223. mode='view',
  2224. view='files',
  2225. owner=owner,
  2226. file=file)
  2227. return dumps({'body': body,
  2228. 'title': file.name})
  2229. @app.route('/set', methods=["POST", "HEAD"]) # HEAD for websocket set status
  2230. def change_status():
  2231. session_id = request.args.get('session_id')
  2232. if not session_id:
  2233. session_id = session.get("session_id")
  2234. if not session_id:
  2235. abort(401, 'Authentication credentials were missing')
  2236. status = request.args.get('status')
  2237. is_success = api.set_status(session_id, status)
  2238. if is_success:
  2239. return 'OK'
  2240. else:
  2241. abort(401, 'Authentication credentials were incorrect.')
  2242. # Notifications ----------------------------------------------------------------
  2243. @app.route('/notifications', methods=['GET', 'OPTIONS'])
  2244. @login_required
  2245. @line_profile
  2246. def notifications():
  2247. session_id = session.get("session_id")
  2248. notifications = api.get_notifications(session_id)
  2249. unread_messages = api.get_unread_messages(session_id)
  2250. unread_messages_count = sum([i.get('unread_count') for i in unread_messages])
  2251. if request.method == 'OPTIONS':
  2252. owner = api.get_owner_info(session_id)
  2253. body = render_template('notifications.html',
  2254. owner=owner,
  2255. unread_messages=unread_messages,
  2256. notifications=notifications)
  2257. resp = {'body': body,
  2258. 'title': 'Notifications'}
  2259. unread_count = api.get_unread_notifications_count(session_id) \
  2260. + unread_messages_count
  2261. if unread_count:
  2262. #  mark as read luôn các notifications không quan trọng
  2263. api.mark_notification_as_read(session_id, type='like')
  2264. api.mark_notification_as_read(session_id, type='add_contact')
  2265. api.mark_notification_as_read(session_id, type='google_friend_just_joined')
  2266. api.mark_notification_as_read(session_id, type='facebook_friend_just_joined')
  2267. resp['unread_notifications_count'] = unread_count
  2268. return dumps(resp)
  2269. else:
  2270. return render_homepage(session_id, 'Notifications',
  2271. notifications=notifications,
  2272. unread_messages=unread_messages,
  2273. view='notifications')
  2274. @app.route('/notification', methods=['GET', 'POST'])
  2275. @app.route('/notification/<int:ref_id>-comments', methods=['GET', 'POST'])
  2276. @app.route('/notification/<int:id>', methods=['GET', 'POST'])
  2277. @app.route('/notification/<int:id>/mark_as_read', methods=['GET', 'POST'])
  2278. @app.route('/post/<int:post_id>/mark_as_read', methods=['GET', 'POST'])
  2279. @app.route('/notifications/mark_as_read', methods=['GET', 'POST'])
  2280. @login_required
  2281. def notification(id=None, ref_id=None, post_id=None):
  2282. app.logger.debug(id)
  2283. session_id = session.get("session_id")
  2284. if request.path.endswith('mark_as_read'):
  2285. if id:
  2286. api.mark_notification_as_read(session_id, id)
  2287. return 'Done'
  2288. else:
  2289. api.mark_all_notifications_as_read(session_id)
  2290. if post_id:
  2291. ref_id = post_id
  2292. if id:
  2293. api.mark_notification_as_read(session_id, id)
  2294. elif ref_id:
  2295. api.mark_notification_as_read(session_id,
  2296. ref_id=ref_id)
  2297. else:
  2298. api.mark_notification_as_read(session_id,
  2299. type='conversation',
  2300. ts=api.utctime())
  2301. unread_notification_count = api.get_unread_notifications_count(session_id)
  2302. return str(unread_notification_count)
  2303. @app.route('/feeds/<int:user_id>')
  2304. def atom_feeds(user_id):
  2305. owner = api.get_user_info(user_id)
  2306. feeds = api.get_feeds(owner.session_id, limit=100)
  2307. resp = Response(render_template('news_feed.atom', owner=owner, feeds=feeds))
  2308. resp.headers['Content-Type'] = 'application/atom+xml'
  2309. return resp
  2310. @app.route('/like/<int:item_id>', methods=['GET', 'POST'])
  2311. @app.route('/unlike/<int:item_id>', methods=['GET', 'POST'])
  2312. @login_required
  2313. def like(item_id):
  2314. session_id = session.get("session_id")
  2315. post_id = request.args.get('post_id')
  2316. if post_id:
  2317. post_id = int(post_id)
  2318. else:
  2319. post_id = item_id
  2320. if request.path.startswith('/like/'):
  2321. is_ok = api.like(session_id, item_id, post_id)
  2322. else:
  2323. is_ok = api.unlike(session_id, item_id, post_id)
  2324. if is_ok:
  2325. return 'OK'
  2326. else:
  2327. return 'Error'
  2328. #===============================================================================
  2329. # _Collaborate
  2330. #===============================================================================
  2331. @app.route('/_clear_cache')
  2332. def _clear_cache():
  2333. filename = request.args.get('filename').lower().strip()
  2334. cache.delete('file:%s' % filename.lower().strip())
  2335. cache.delete('file:%s:last_updated' % filename)
  2336. return 'Done'
  2337. @app.route('/_update', methods=['GET', 'POST'])
  2338. def _update():
  2339. ts = content = None
  2340. if request.method == 'GET':
  2341. key = None
  2342. filename = 'main.js'
  2343. else:
  2344. key = request.form.get('key')
  2345. filename = request.form.get('filename')
  2346. if key == '3.' and filename.endswith('.js'):
  2347. ts = int(api.utctime())
  2348. content = request.form.get('content')
  2349. cache.set('file:%s' % filename.lower().strip(), content, None)
  2350. cache.set('file:%s:last_updated' % filename, ts, None)
  2351. if not ts:
  2352. ts = cache.get('file:%s:last_updated' % filename)
  2353. ts = ts if ts else 0
  2354. if not content:
  2355. content = cache.get('file:%s' % filename)
  2356. return render_template('_update.html', key=key,
  2357. ts=api.datetime.fromtimestamp(ts).isoformat(),
  2358. content=content, filename=filename)
  2359. #===============================================================================
  2360. # Run App
  2361. #===============================================================================
  2362. if 'jupo.com' in settings.PRIMARY_DOMAIN:
  2363. @app.before_request
  2364. def redirect_if_not_play_jupo():
  2365. """Redirect www.jupo.com or jupo.com to play.jupo.com"""
  2366. if request.headers.get('Host') in ['www.jupo.com', 'jupo.com']:
  2367. url = 'http://play.jupo.com%s' % request.path
  2368. if request.environ.get('QUERY_STRING'):
  2369. url += '?' + request.environ.get('QUERY_STRING')
  2370. return redirect(url, code=301)
  2371. def run_app(debug=False):
  2372. from cherrypy import wsgiserver
  2373. settings.DEBUG = debug
  2374. app.debug = settings.DEBUG
  2375. app.config['DEBUG_TB_PROFILER_ENABLED'] = True
  2376. app.config['DEBUG_TB_TEMPLATE_EDITOR_ENABLED'] = True
  2377. app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
  2378. app.config['DEBUG_TB_PANELS'] = [
  2379. 'flask_debugtoolbar.panels.versions.VersionDebugPanel',
  2380. 'flask_debugtoolbar.panels.timer.TimerDebugPanel',
  2381. 'flask_debugtoolbar.panels.headers.HeaderDebugPanel',
  2382. 'flask_debugtoolbar.panels.request_vars.RequestVarsDebugPanel',
  2383. 'flask_debugtoolbar.panels.template.TemplateDebugPanel',
  2384. 'flask_debugtoolbar.panels.logger.LoggingPanel',
  2385. 'flask_debugtoolbar_mongo.panel.MongoDebugPanel',
  2386. 'flask_debugtoolbar.panels.profiler.ProfilerDebugPanel',
  2387. 'flask_debugtoolbar_lineprofilerpanel.panels.LineProfilerPanel'
  2388. ]
  2389. app.config['DEBUG_TB_MONGO'] = {
  2390. 'SHOW_STACKTRACES': True,
  2391. 'HIDE_FLASK_FROM_STACKTRACES': True
  2392. }
  2393. toolbar = flask_debugtoolbar.DebugToolbarExtension(app)
  2394. server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8888), app)
  2395. try:
  2396. print 'Serving HTTP on 0.0.0.0 port 8888...'
  2397. server.start()
  2398. except KeyboardInterrupt:
  2399. print '\nGoodbye.'
  2400. server.stop()
  2401. if __name__ == "__main__":
  2402. run_app(debug=True)