~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/util.py

  • Committer: Robert Collins
  • Date: 2012-02-02 07:42:24 UTC
  • Revision ID: robertc@robertcollins.net-20120202074224-ujea2ocm1u1ws1en
    - Make tz calculations consistent and use UTC in the UI everywhere we show
      a precise timestamp. (Robert Collins, #594591)

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
#
21
21
 
22
22
import base64
23
 
import cgi
24
23
import datetime
25
24
import logging
26
25
import re
53
52
# Display of times.
54
53
 
55
54
# date_day -- just the day
56
 
# date_time -- full date with time
 
55
# date_time -- full date with time (UTC)
57
56
#
58
 
# displaydate -- for use in sentences
59
57
# approximatedate -- for use in tables
60
58
#
61
 
# displaydate and approximatedate return an elementtree <span> Element
62
 
# with the full date in a tooltip.
 
59
# approximatedate return an elementtree <span> Element
 
60
# with the full date (UTC) in a tooltip.
63
61
 
64
62
 
65
63
def date_day(value):
68
66
 
69
67
def date_time(value):
70
68
    if value is not None:
71
 
        return value.strftime('%Y-%m-%d %H:%M:%S')
 
69
        # Note: this assumes that the value is UTC in some fashion.
 
70
        return value.strftime('%Y-%m-%d %H:%M:%S UTC')
72
71
    else:
73
72
        return 'N/A'
74
73
 
75
74
 
76
 
def _displaydate(date):
77
 
    delta = abs(datetime.datetime.now() - date)
78
 
    if delta > datetime.timedelta(1, 0, 0):
79
 
        # far in the past or future, display the date
80
 
        return 'on ' + date_day(date)
81
 
    return _approximatedate(date)
82
 
 
83
 
 
84
75
def _approximatedate(date):
85
76
    delta = datetime.datetime.now() - date
86
77
    if abs(delta) > datetime.timedelta(1, 0, 0):
127
118
    return _wrap_with_date_time_title(date, _approximatedate(date))
128
119
 
129
120
 
130
 
def displaydate(date):
131
 
    return _wrap_with_date_time_title(date, _displaydate(date))
132
 
 
133
 
 
134
121
class Container(object):
135
122
    """
136
123
    Convert a dict into an object with attributes.
214
201
# only do this if unicode turns out to be a problem
215
202
#_BADCHARS_RE = re.compile(ur'[\u007f-\uffff]')
216
203
 
 
204
# Can't be a dict; &amp; needs to be done first.
 
205
html_entity_subs = [
 
206
    ("&", "&amp;"),
 
207
    ('"', "&quot;"),
 
208
    ("'", "&#39;"), # &apos; is defined in XML, but not HTML.
 
209
    (">", "&gt;"),
 
210
    ("<", "&lt;"),
 
211
    ]
 
212
 
 
213
 
 
214
def html_escape(s):
 
215
    """Transform dangerous (X)HTML characters into entities.
 
216
 
 
217
    Like cgi.escape, except also escaping \" and '. This makes it safe to use
 
218
    in both attribute and element content.
 
219
 
 
220
    If you want to safely fill a format string with escaped values, use
 
221
    html_format instead
 
222
    """
 
223
    for char, repl in html_entity_subs:
 
224
        s = s.replace(char, repl)
 
225
    return s
 
226
 
 
227
 
 
228
def html_format(template, *args):
 
229
    """Safely format an HTML template string, escaping the arguments.
 
230
 
 
231
    The template string must not be user-controlled; it will not be escaped.
 
232
    """
 
233
    return template % tuple(html_escape(arg) for arg in args)
 
234
 
 
235
 
217
236
# FIXME: get rid of this method; use fixed_width() and avoid XML().
218
237
 
219
 
 
220
238
def html_clean(s):
221
239
    """
222
240
    clean up a string for html display.  expand any tabs, encode any html
223
241
    entities, and replace spaces with '&nbsp;'.  this is primarily for use
224
242
    in displaying monospace text.
225
243
    """
226
 
    s = cgi.escape(s.expandtabs())
 
244
    s = html_escape(s.expandtabs())
227
245
    s = s.replace(' ', '&nbsp;')
228
246
    return s
229
247
 
269
287
        except UnicodeDecodeError:
270
288
            s = s.decode('iso-8859-15')
271
289
 
272
 
    s = cgi.escape(s).expandtabs().replace(' ', NONBREAKING_SPACE)
 
290
    s = html_escape(s).expandtabs().replace(' ', NONBREAKING_SPACE)
273
291
 
274
292
    return HSC.clean(s).replace('\n', '<br/>')
275
293
 
454
472
    for index, dir_name in enumerate(dir_parts):
455
473
        inner_breadcrumbs.append({
456
474
            'dir_name': dir_name,
457
 
            'file_id': inv.path2id('/'.join(dir_parts[:index + 1])),
 
475
            'path': '/'.join(dir_parts[:index + 1]),
458
476
            'suffix': '/' + view,
459
477
        })
460
478
    return inner_breadcrumbs
525
543
#         for re-ordering an existing page by different sort
526
544
 
527
545
t_context = threading.local()
528
 
_valid = ('start_revid', 'file_id', 'filter_file_id', 'q', 'remember',
529
 
          'compare_revid', 'sort')
 
546
_valid = (
 
547
    'start_revid', 'filter_file_id', 'q', 'remember', 'compare_revid', 'sort')
530
548
 
531
549
 
532
550
def set_context(map):
633
651
            else:
634
652
                raise
635
653
    return new_application
 
654
 
 
655
 
 
656
def convert_to_json_ready(obj):
 
657
    if isinstance(obj, Container):
 
658
        d = obj.__dict__.copy()
 
659
        del d['_properties']
 
660
        return d
 
661
    elif isinstance(obj, datetime.datetime):
 
662
        return tuple(obj.utctimetuple())
 
663
    raise TypeError(repr(obj) + " is not JSON serializable")