Package spammcan :: Module util
[hide private]

Source Code for Module spammcan.util

  1  """Miscellaneous utility functions.""" 
  2   
  3  __all__ = [ 
  4      'absolute_url', 
  5      'add_global_tmpl_vars', 
  6      'code2html', 
  7      'get_user_id', 
  8      'get_server_name', 
  9      'get_static_content', 
 10      'message_of_the_day', 
 11      'txt2html', 
 12      'wrap_text', 
 13  ] 
 14   
 15  import logging 
 16  import random 
 17  import textwrap 
 18   
 19  from os.path import join 
 20   
 21  import cherrypy 
 22  from turbogears import config, identity, url 
 23  from turbogears.release import version as tg_version 
 24  from pygments import highlight 
 25  from pygments.lexers import get_lexer_by_name 
 26  from pygments.styles import get_style_by_name 
 27  from pygments.formatters import HtmlFormatter 
 28   
 29  try: 
 30      from spammcan.rest import HTML 
 31      config.update({'has_docutils': True}) 
 32  except ImportError: 
 33      config.update({'has_docutils': False}) 
 34   
 35   
 36  log = logging.getLogger('spammcan.controllers') 
 37  _static_dir = config.get('static_filter.dir', path='/static') 
 38   
 39   
40 -def absolute_url(tgpath='/', params=None, **kw):
41 """Returns absolute URL (including schema and host to this server). 42 43 Tries to account for 'Host' header and reverse proxing ('X-Forwarded-Host'). 44 45 """ 46 47 h = cherrypy.request.headers 48 use_xfh = config.get('base_url_filter.use_x_forwarded_host', False) 49 if h.get('X-Use-SSL'): 50 scheme = 'https' 51 else: 52 scheme = cherrypy.request.scheme 53 base_url = '%s://%s' % (scheme, get_server_name()) 54 if config.get('base_url_filter.on', False) and not use_xfh: 55 base_url = config.get('base_url_filter.base_url').rstrip('/') 56 return '%s%s' % (base_url, url(tgpath, params, **kw))
57
58 -def add_global_tmpl_vars(vars):
59 """Add custom global template variables. 60 61 Adds the following variables: 62 63 ``tg.motd`` - The message of the day as a plain string 64 65 """ 66 vars['motd'] = message_of_the_day() 67 vars['abs_url'] = absolute_url 68 vars['tg_version'] = tg_version
69
70 -def code2html(code, format, style=None, cssclass="source", hl_lines=None, 71 linenos=False):
72 """Syntax highlight given code with Pygments and format as HTML.""" 73 formatter_options = dict( 74 style=style or 'default', 75 linenos=linenos, 76 cssclass=cssclass, 77 lineanchors='L') 78 if hl_lines: 79 formatter_options['hl_lines'] = hl_lines 80 lexer = get_lexer_by_name(format) 81 formatter = HtmlFormatter(**formatter_options) 82 return highlight(code, lexer, formatter), formatter.get_style_defs( 83 '.' + cssclass)
84
85 -def get_user_id():
86 """Return id of current visitor. 87 88 This will be a string with 32-char MD5 hash, which will be retrieved either 89 from a request cookie or default to the visit_key of the current identity. 90 91 As a side affect this function sets a response cookie for the user ID 92 called 'spammcan_uid' with an expiry time set by the 93 'spammcan.uid_cookie_expiry' config setting (defaults to 90 days). 94 95 """ 96 cookie = cherrypy.request.simple_cookie.get('spammcan_uid') 97 log.debug("User ID cookie: %r", cookie) 98 if cookie: 99 uid = cookie.value 100 else: 101 uid = identity.current.visit_key 102 cherrypy.response.simple_cookie['spammcan_uid'] = uid 103 cherrypy.response.simple_cookie['spammcan_uid']['expires'] = config.get( 104 'spammcan.uid_cookie_expiry', 3600*24*90) 105 return uid
106
107 -def get_server_name():
108 """Return name of the server this application runs on. 109 110 Tries to account for 'Host' header and reverse proxing. 111 112 """ 113 h = cherrypy.request.headers 114 return config.get('server.domain', h.get('X-Forwarded-Host', h['Host']))
115
116 -def get_static_content(name):
117 """Read text file from static directory and convert it to HTML.""" 118 filename = join(_static_dir, name) 119 try: 120 fo = open(filename, 'rb') 121 except (OSError, IOError): 122 text = _(u"Could not read static content resource '%s'.") % name 123 else: 124 text = fo.read().decode('utf-8') 125 fo.close() 126 return txt2html(text)
127
128 -def message_of_the_day(filename='tipoftheday.txt'):
129 """Return random message of the day from a text file with one msg per line. 130 """ 131 totd = join(_static_dir, filename) 132 return random.choice(filter(None, open(totd).readlines()))
133
134 -def txt2html(text, use_docutils=True):
135 """Try to convert text into HTML with docutils. 136 137 If conversion fails or using docutils is turned off by the configuration, 138 return text wrapped in a PRE element with CSS class "plaintext". 139 140 """ 141 use_docutils = use_docutils and config.get('has_docutils', False) 142 if use_docutils: 143 try: 144 text = HTML(text, report_level=0, initial_header_level=2) 145 except Exception, exc: 146 log.debug("txt2html failed: %r,", exc) 147 use_docutils = False 148 return use_docutils and text or '<pre class="plaintext">%s</pre>' % text
149
150 -def _wrap_line(s, width=100):
151 """Wrap single paragraph of text with custom options.""" 152 return textwrap.wrap(s, width=width, subsequent_indent=' ', 153 expand_tabs=True, replace_whitespace=False, break_long_words=False)
154
155 -def wrap_text(s, width=100):
156 """Wrap each paragraph in s with wrap(). 157 158 Returns 2-item tuple with a list of line nummers of continuation lines, and 159 the wrapped text. 160 161 """ 162 i = 1; wrapped_lines = []; output= [] 163 for line in s.splitlines(): 164 newlines = _wrap_line(line, width) or [''] 165 if len(newlines) > 1: 166 wrapped_lines.extend(range(i+1,i+len(newlines))) 167 i += len(newlines) 168 output.extend(newlines) 169 return wrapped_lines, "\n".join(output)
170