]> git.openstreetmap.org Git - osqa.git/blob - forum/templatetags/extra_tags.py
76935fe448d3fe753fe6c1d9402c03b8aeadcde9
[osqa.git] / forum / templatetags / extra_tags.py
1 import time
2 import os
3 import posixpath
4 import datetime
5 import math
6 import re
7 import logging
8 from django import template
9 from django.utils.encoding import smart_unicode
10 from django.utils.safestring import mark_safe
11 from forum.models import Question, Answer, QuestionRevision, AnswerRevision, NodeRevision
12 from django.utils.translation import ugettext as _
13 from django.utils.translation import ungettext
14 from django.utils import simplejson
15 from forum import settings
16 from django.template.defaulttags import url as default_url
17 from forum import skins
18 from forum.utils import html
19 from extra_filters import decorated_int
20 from django.core.urlresolvers import reverse
21
22 register = template.Library()
23
24 GRAVATAR_TEMPLATE = ('<img class="gravatar" width="%(size)s" height="%(size)s" '
25 'src="http://www.gravatar.com/avatar/%(gravatar_hash)s'
26 '?s=%(size)s&amp;d=%(default)s&amp;r=%(rating)s" '
27 'alt="%(username)s\'s gravatar image" />')
28
29 @register.simple_tag
30 def gravatar(user, size):
31     try:
32         gravatar = user['gravatar']
33         username = user['username']
34     except (TypeError, AttributeError, KeyError):
35         gravatar = user.gravatar
36         username = user.username
37     return mark_safe(GRAVATAR_TEMPLATE % {
38     'size': size,
39     'gravatar_hash': gravatar,
40     'default': settings.GRAVATAR_DEFAULT_IMAGE,
41     'rating': settings.GRAVATAR_ALLOWED_RATING,
42     'username': template.defaultfilters.urlencode(username),
43     })
44
45
46 @register.simple_tag
47 def get_score_badge(user):
48     if user.is_suspended():
49         return _("(suspended)")
50
51     repstr = decorated_int(user.reputation, "")
52
53     BADGE_TEMPLATE = '<span class="score" title="%(reputation)s %(reputationword)s">%(repstr)s</span>'
54     if user.gold > 0 :
55         BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(gold)s %(badgesword)s">'
56         '<span class="badge1">&#9679;</span>'
57         '<span class="badgecount">%(gold)s</span>'
58         '</span>')
59     if user.silver > 0:
60         BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(silver)s %(badgesword)s">'
61         '<span class="silver">&#9679;</span>'
62         '<span class="badgecount">%(silver)s</span>'
63         '</span>')
64     if user.bronze > 0:
65         BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(bronze)s %(badgesword)s">'
66         '<span class="bronze">&#9679;</span>'
67         '<span class="badgecount">%(bronze)s</span>'
68         '</span>')
69     BADGE_TEMPLATE = smart_unicode(BADGE_TEMPLATE, encoding='utf-8', strings_only=False, errors='strict')
70     return mark_safe(BADGE_TEMPLATE % {
71     'reputation' : user.reputation,
72     'repstr': repstr,
73     'gold' : user.gold,
74     'silver' : user.silver,
75     'bronze' : user.bronze,
76     'badgesword' : _('badges'),
77     'reputationword' : _('reputation points'),
78     })
79
80
81 @register.simple_tag
82 def get_age(birthday):
83     current_time = datetime.datetime(*time.localtime()[0:6])
84     year = birthday.year
85     month = birthday.month
86     day = birthday.day
87     diff = current_time - datetime.datetime(year, month, day, 0, 0, 0)
88     return diff.days / 365
89
90 @register.simple_tag
91 def diff_date(date, limen=2):
92     if not date:
93         return _('unknown')
94
95     now = datetime.datetime.now()
96     diff = now - date
97     days = diff.days
98     hours = int(diff.seconds/3600)
99     minutes = int(diff.seconds/60)
100
101     if days > 2:
102         if date.year == now.year:
103             return date.strftime(_("%b %d at %H:%M").encode())
104         else:
105             return date.strftime(_("%b %d '%y at %H:%M").encode())
106     elif days == 2:
107         return _('2 days ago')
108     elif days == 1:
109         return _('yesterday')
110     elif minutes >= 60:
111         return ungettext('%(hr)d ' + _("hour ago"), '%(hr)d ' + _("hours ago"), hours) % {'hr':hours}
112     elif diff.seconds >= 60:
113         return ungettext('%(min)d ' + _("min ago"), '%(min)d ' + _("mins ago"), minutes) % {'min':minutes}
114     else:
115         return ungettext('%(sec)d ' + _("sec ago"), '%(sec)d ' + _("secs ago"), diff.seconds) % {'sec':diff.seconds}
116
117 @register.simple_tag
118 def media(url):
119     url = skins.find_media_source(url)
120     if url:
121         # Create the URL prefix.
122         url_prefix = settings.FORCE_SCRIPT_NAME + '/m/'
123
124         # Make sure any duplicate forward slashes are replaced with a single
125         # forward slash.
126         url_prefix = re.sub("/+", "/", url_prefix)
127
128         url = url_prefix + url
129         return url
130
131 class ItemSeparatorNode(template.Node):
132     def __init__(self, separator):
133         sep = separator.strip()
134         if sep[0] == sep[-1] and sep[0] in ('\'', '"'):
135             sep = sep[1:-1]
136         else:
137             raise template.TemplateSyntaxError('separator in joinitems tag must be quoted')
138         self.content = sep
139
140     def render(self, context):
141         return self.content
142
143 class BlockMediaUrlNode(template.Node):
144     def __init__(self, nodelist):
145         self.items = nodelist
146
147     def render(self, context):
148         prefix = settings.APP_URL + 'm/'
149         url = ''
150         if self.items:
151             url += '/'
152         for item in self.items:
153             url += item.render(context)
154
155         url = skins.find_media_source(url)
156         url = prefix + url
157         out = url
158         return out.replace(' ', '')
159
160 @register.tag(name='blockmedia')
161 def blockmedia(parser, token):
162     try:
163         tagname = token.split_contents()
164     except ValueError:
165         raise template.TemplateSyntaxError("blockmedia tag does not use arguments")
166     nodelist = []
167     while True:
168         nodelist.append(parser.parse(('endblockmedia')))
169         next = parser.next_token()
170         if next.contents == 'endblockmedia':
171             break
172     return BlockMediaUrlNode(nodelist)
173
174
175 @register.simple_tag
176 def fullmedia(url):
177     domain = settings.APP_BASE_URL
178     #protocol = getattr(settings, "PROTOCOL", "http")
179     path = media(url)
180     return "%s%s" % (domain, path)
181
182
183 class SimpleVarNode(template.Node):
184     def __init__(self, name, value):
185         self.name = name
186         self.value = template.Variable(value)
187
188     def render(self, context):
189         context[self.name] = self.value.resolve(context)
190         return ''
191
192 class BlockVarNode(template.Node):
193     def __init__(self, name, block):
194         self.name = name
195         self.block = block
196
197     def render(self, context):
198         source = self.block.render(context)
199         context[self.name] = source.strip()
200         return ''
201
202
203 @register.tag(name='var')
204 def do_var(parser, token):
205     tokens = token.split_contents()[1:]
206
207     if not len(tokens) or not re.match('^\w+$', tokens[0]):
208         raise template.TemplateSyntaxError("Expected variable name")
209
210     if len(tokens) == 1:
211         nodelist = parser.parse(('endvar',))
212         parser.delete_first_token()
213         return BlockVarNode(tokens[0], nodelist)
214     elif len(tokens) == 3:
215         return SimpleVarNode(tokens[0], tokens[2])
216
217     raise template.TemplateSyntaxError("Invalid number of arguments")
218
219 class DeclareNode(template.Node):
220     dec_re = re.compile('^\s*(\w+)\s*(:?=)\s*(.*)$')
221
222     def __init__(self, block):
223         self.block = block
224
225     def render(self, context):
226         source = self.block.render(context)
227
228         for line in source.splitlines():
229             m = self.dec_re.search(line)
230             if m:
231                 clist = list(context)
232                 clist.reverse()
233                 d = {}
234                 d['_'] = _
235                 d['os'] = os
236                 d['html'] = html
237                 d['reverse'] = reverse
238                 for c in clist:
239                     d.update(c)
240                 try:
241                     context[m.group(1).strip()] = eval(m.group(3).strip(), d)
242                 except Exception, e:
243                     logging.error("Error in declare tag, when evaluating: %s" % m.group(3).strip())
244                     raise
245         return ''
246
247 @register.tag(name='declare')
248 def do_declare(parser, token):
249     nodelist = parser.parse(('enddeclare',))
250     parser.delete_first_token()
251     return DeclareNode(nodelist)