PageRenderTime 71ms CodeModel.GetById 36ms RepoModel.GetById 4ms app.codeStats 0ms

/pypress/views/base.py

https://github.com/laoqiu/pypress-tornado
Python | 202 lines | 184 code | 5 blank | 13 comment | 0 complexity | 4048ffaed45aa98deb3574ae83480c96 MD5 | raw file
  1. #!/usr/bin/env python
  2. #coding=utf-8
  3. """
  4. views: base.py
  5. ~~~~~~~~~~~
  6. :author: laoqiu.com@gmail.com
  7. """
  8. import os
  9. import logging
  10. import tornado.web
  11. import tornado.locale
  12. import tornado.escape
  13. import tornado.ioloop
  14. from pygments import highlight
  15. from pygments.lexers import get_lexer_for_filename
  16. from pygments.formatters import HtmlFormatter
  17. from pypress.database import db
  18. from pypress.models import Comment, Tag, Link
  19. from pypress.extensions.permission import Identity, AnonymousIdentity
  20. from pypress.extensions.cache import cache
  21. from pypress.extensions.sessions import RedisSession, Session
  22. class FlashMessageMixIn(object):
  23. """
  24. Store a message between requests which the user needs to see.
  25. views
  26. -------
  27. self.flash("Welcome back, %s" % username, 'success')
  28. base.html
  29. ------------
  30. {% set messages = handler.get_flashed_messages() %}
  31. {% if messages %}
  32. <div id="flashed">
  33. {% for category, msg in messages %}
  34. <span class="flash-{{ category }}">{{ msg }}</span>
  35. {% end %}
  36. </div>
  37. {% end %}
  38. """
  39. def flash(self, message, category='message'):
  40. messages = self.messages()
  41. messages.append((category, message))
  42. self.set_secure_cookie('flash_messages', tornado.escape.json_encode(messages))
  43. def messages(self):
  44. messages = self.get_secure_cookie('flash_messages')
  45. messages = tornado.escape.json_decode(messages) if messages else []
  46. return messages
  47. def get_flashed_messages(self):
  48. messages = self.messages()
  49. self.clear_cookie('flash_messages')
  50. return messages
  51. class PermissionMixIn(object):
  52. @property
  53. def identity(self):
  54. if not hasattr(self, "_identity"):
  55. self._identity = self.get_identity()
  56. return self._identity
  57. def get_identity(self):
  58. if self.current_user:
  59. identity = Identity(self.current_user.id)
  60. identity.provides.update(self.current_user.provides)
  61. return identity
  62. return AnonymousIdentity()
  63. class CachedItemsMixIn(object):
  64. def get_cached_items(self, name):
  65. items = cache.get(name)
  66. if items is None:
  67. items = self.set_cached_items(name)
  68. return items
  69. def set_cached_items(self, name, limit=10):
  70. items = []
  71. if name == 'latest_comments':
  72. items = [comment.item for comment in Comment.query.order_by(Comment.created_date.desc()).limit(limit)]
  73. elif name == 'tags':
  74. items = Tag.query.cloud()
  75. elif name == 'links':
  76. items = [link.item for link in Link.query.filter(Link.passed==True).limit(limit)]
  77. cache.set(name, items)
  78. return items
  79. class RequestHandler(tornado.web.RequestHandler, PermissionMixIn, FlashMessageMixIn, CachedItemsMixIn):
  80. def on_finish(self):
  81. """sqlalchemy connection close.
  82. fixed sqlalchemy error: 'Can't reconnect until invalid'. new in version 2.2"""
  83. db.session.remove()
  84. def get_current_user(self):
  85. user = self.session['user'] if 'user' in self.session else None
  86. return user
  87. @property
  88. def session(self):
  89. if hasattr(self, '_session'):
  90. return self._session
  91. else:
  92. self.require_setting('permanent_session_lifetime', 'session')
  93. expires = self.settings['permanent_session_lifetime'] or None
  94. if 'redis_server' in self.settings and self.settings['redis_server']:
  95. sessionid = self.get_secure_cookie('sid')
  96. self._session = RedisSession(self.application.session_store, sessionid, expires_days=expires)
  97. if not sessionid:
  98. self.set_secure_cookie('sid', self._session.id, expires_days=expires)
  99. else:
  100. self._session = Session(self.get_secure_cookie, self.set_secure_cookie, expires_days=expires)
  101. return self._session
  102. def get_user_locale(self):
  103. code = self.get_cookie('lang', self.settings.get('default_locale', 'zh_CN'))
  104. return tornado.locale.get(code)
  105. def get_template_path(self):
  106. if 'theme_template_path' in self.settings:
  107. return self.settings['theme_template_path']
  108. return self.settings.get('template_path')
  109. def get_error_html(self, status_code, **kwargs):
  110. if self.settings.get('debug', False) is False:
  111. self.set_status(status_code)
  112. return self.render_string('errors/%s.html' % status_code)
  113. else:
  114. def get_snippet(fp, target_line, num_lines):
  115. if fp.endswith('.html'):
  116. fp = os.path.join(self.get_template_path(), fp)
  117. half_lines = (num_lines/2)
  118. try:
  119. with open(fp) as f:
  120. all_lines = [line for line in f]
  121. code = ''.join(all_lines[target_line-half_lines-1:target_line+half_lines])
  122. formatter = HtmlFormatter(linenos=True, linenostart=target_line-half_lines, hl_lines=[half_lines+1])
  123. lexer = get_lexer_for_filename(fp)
  124. return highlight(code, lexer, formatter)
  125. except Exception, ex:
  126. logging.error(ex)
  127. return ''
  128. css = HtmlFormatter().get_style_defs('.highlight')
  129. exception = kwargs.get('exception', None)
  130. return self.render_string('errors/exception.htm',
  131. get_snippet=get_snippet,
  132. css=css,
  133. exception=exception,
  134. status_code=status_code,
  135. kwargs=kwargs)
  136. def get_args(self, key, default=None, type=None):
  137. if type==list:
  138. if default is None: default = []
  139. return self.get_arguments(key, default)
  140. value = self.get_argument(key, default)
  141. if value and type:
  142. try:
  143. value = type(value)
  144. except ValueError:
  145. value = default
  146. return value
  147. @property
  148. def is_xhr(self):
  149. '''True if the request was triggered via a JavaScript XMLHttpRequest.
  150. This only works with libraries that support the `X-Requested-With`
  151. header and set it to "XMLHttpRequest". Libraries that do that are
  152. prototype, jQuery and Mochikit and probably some more.'''
  153. return self.request.headers.get('X-Requested-With', '') \
  154. .lower() == 'xmlhttprequest'
  155. @property
  156. def forms(self):
  157. return self.application.forms[self.locale.code]
  158. def _(self, message, plural_message=None, count=None):
  159. return self.locale.translate(message, plural_message, count)
  160. class ErrorHandler(RequestHandler):
  161. """raise 404 error if url is not found.
  162. fixed tornado.web.RequestHandler HTTPError bug.
  163. """
  164. def prepare(self):
  165. self.set_status(404)
  166. raise tornado.web.HTTPError(404)