root / snf-astakos-app / astakos / im / templatetags / astakos_tags.py @ 4e03ba30
History | View | Annotate | Download (9.9 kB)
1 |
# Copyright 2011 GRNET S.A. All rights reserved.
|
---|---|
2 |
#
|
3 |
# Redistribution and use in source and binary forms, with or
|
4 |
# without modification, are permitted provided that the following
|
5 |
# conditions are met:
|
6 |
#
|
7 |
# 1. Redistributions of source code must retain the above
|
8 |
# copyright notice, this list of conditions and the following
|
9 |
# disclaimer.
|
10 |
#
|
11 |
# 2. Redistributions in binary form must reproduce the above
|
12 |
# copyright notice, this list of conditions and the following
|
13 |
# disclaimer in the documentation and/or other materials
|
14 |
# provided with the distribution.
|
15 |
#
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 |
# POSSIBILITY OF SUCH DAMAGE.
|
28 |
#
|
29 |
# The views and conclusions contained in the software and
|
30 |
# documentation are those of the authors and should not be
|
31 |
# interpreted as representing official policies, either expressed
|
32 |
# or implied, of GRNET S.A.
|
33 |
|
34 |
import urllib |
35 |
|
36 |
from inspect import getargspec |
37 |
|
38 |
from django import template |
39 |
from django.core.urlresolvers import resolve |
40 |
from django.conf import settings |
41 |
from django.template import TemplateSyntaxError, Variable |
42 |
from django.utils.translation import ugettext as _ |
43 |
from django.template.loader import render_to_string |
44 |
from django.template import RequestContext |
45 |
from django.core.urlresolvers import reverse |
46 |
from django.utils.safestring import mark_safe |
47 |
|
48 |
register = template.Library() |
49 |
|
50 |
MESSAGES_VIEWS_MAP = getattr(settings, 'ASTAKOS_MESSAGES_VIEWS_MAP', { |
51 |
'astakos.im.views.index': 'LOGIN_MESSAGES', |
52 |
'astakos.im.views.logout': 'LOGIN_MESSAGES', |
53 |
'astakos.im.views.login': 'LOGIN_MESSAGES', |
54 |
'astakos.im.views.signup': 'SIGNUP_MESSAGES', |
55 |
'astakos.im.views.edit_profile': 'PROFILE_MESSAGES', |
56 |
'astakos.im.views.change_password': 'PROFILE_MESSAGES', |
57 |
'astakos.im.views.invite': 'PROFILE_MESSAGES', |
58 |
'astakos.im.views.feedback': 'PROFILE_MESSAGES', |
59 |
}) |
60 |
|
61 |
|
62 |
# helper tag decorator
|
63 |
# https://github.com/djblets/djblets/blob/master/djblets/util/decorators.py#L96
|
64 |
def basictag(takes_context=False): |
65 |
"""
|
66 |
A decorator similar to Django's @register.simple_tag that optionally
|
67 |
takes a context parameter. This condenses many tag implementations down
|
68 |
to a few lines of code.
|
69 |
|
70 |
Example:
|
71 |
@register.tag
|
72 |
@basictag(takes_context=True)
|
73 |
def printuser(context):
|
74 |
return context['user']
|
75 |
"""
|
76 |
class BasicTagNode(template.Node): |
77 |
def __init__(self, take_context, tag_name, tag_func, args): |
78 |
self.takes_context = takes_context
|
79 |
self.tag_name = tag_name
|
80 |
self.tag_func = tag_func
|
81 |
self.args = args
|
82 |
|
83 |
def render(self, context): |
84 |
args = [Variable(var).resolve(context) for var in self.args] |
85 |
|
86 |
if self.takes_context: |
87 |
return self.tag_func(context, *args) |
88 |
else:
|
89 |
return self.tag_func(*args) |
90 |
|
91 |
def basictag_func(tag_func): |
92 |
def _setup_tag(parser, token): |
93 |
bits = token.split_contents() |
94 |
tag_name = bits[0]
|
95 |
del(bits[0]) |
96 |
|
97 |
params, xx, xxx, defaults = getargspec(tag_func) |
98 |
max_args = len(params)
|
99 |
|
100 |
if takes_context:
|
101 |
if params[0] == 'context': |
102 |
max_args -= 1 # Ignore context |
103 |
else:
|
104 |
raise TemplateSyntaxError, \
|
105 |
"Any tag function decorated with takes_context=True " \
|
106 |
"must have a first argument of 'context'"
|
107 |
|
108 |
min_args = max_args - len(defaults or []) |
109 |
|
110 |
if not min_args <= len(bits) <= max_args: |
111 |
if min_args == max_args:
|
112 |
raise TemplateSyntaxError, \
|
113 |
"%r tag takes %d arguments." % (tag_name, min_args)
|
114 |
else:
|
115 |
raise TemplateSyntaxError, \
|
116 |
"%r tag takes %d to %d arguments, got %d." % \
|
117 |
(tag_name, min_args, max_args, len(bits))
|
118 |
|
119 |
return BasicTagNode(takes_context, tag_name, tag_func, bits)
|
120 |
|
121 |
_setup_tag.__name__ = tag_func.__name__ |
122 |
_setup_tag.__doc__ = tag_func.__doc__ |
123 |
_setup_tag.__dict__.update(tag_func.__dict__) |
124 |
return _setup_tag
|
125 |
|
126 |
return basictag_func
|
127 |
|
128 |
|
129 |
@register.tag(name='display_messages') |
130 |
def display_messages(parser, token): |
131 |
return MessagesNode()
|
132 |
|
133 |
|
134 |
class DummyMessage(object): |
135 |
def __init__(self, type, msg): |
136 |
self.message = msg
|
137 |
self.tags = type |
138 |
|
139 |
def __repr__(self): |
140 |
return "%s: %s" % (self.tags, self.message) |
141 |
|
142 |
|
143 |
class MessagesNode(template.Node): |
144 |
|
145 |
def get_view_messages(self, context): |
146 |
messages = list(context['GLOBAL_MESSAGES']) |
147 |
try:
|
148 |
view = resolve(context['request'].get_full_path())[0] |
149 |
view_name = "%s.%s" % (view.__module__, view.func_name)
|
150 |
messages += context[MESSAGES_VIEWS_MAP.get(view_name)] |
151 |
return messages
|
152 |
except Exception, e: |
153 |
return messages
|
154 |
|
155 |
def render(self, context): |
156 |
if self not in context.render_context: |
157 |
messages = list(context['messages']) |
158 |
if context['EXTRA_MESSAGES_SET']: |
159 |
view_messages = self.get_view_messages(context)
|
160 |
for msg_object in view_messages: |
161 |
messages.append(DummyMessage(msg_object[0], msg_object[1])) |
162 |
|
163 |
if not messages: |
164 |
return "" |
165 |
|
166 |
cls = messages[-1].tags
|
167 |
content = '<div class="top-msg active %s">' % cls
|
168 |
for msg in messages: |
169 |
content += '<div class="msg %s">%s</div>' % (
|
170 |
msg.tags, msg.message) |
171 |
|
172 |
content += '<a href="#" title="close" class="close">X</a>'
|
173 |
content += '</div>'
|
174 |
context.render_context[self] = content
|
175 |
|
176 |
return context.render_context[self] |
177 |
|
178 |
|
179 |
@register.simple_tag
|
180 |
def get_grant_value(rname, form): |
181 |
grants = form.instance.grants |
182 |
try:
|
183 |
r = form.instance.projectresourcegrant_set.get(resource__name=rname).member_capacity |
184 |
except Exception, e: |
185 |
r = ''
|
186 |
return r
|
187 |
|
188 |
@register.tag(name="provider_login_url") |
189 |
@basictag(takes_context=True) |
190 |
def provider_login_url(context, provider, from_login=False): |
191 |
request = context['request'].REQUEST
|
192 |
next = request.get('next', None) |
193 |
code = request.get('code', None) |
194 |
key = request.get('key', None) |
195 |
|
196 |
attrs = {} |
197 |
if next: |
198 |
attrs['next'] = next |
199 |
if code:
|
200 |
attrs['code'] = code
|
201 |
if key:
|
202 |
attrs['key'] = key
|
203 |
if from_login:
|
204 |
attrs['from_login'] = 1 |
205 |
|
206 |
url = provider.urls.get('login')
|
207 |
|
208 |
joinchar = "?"
|
209 |
if "?" in url: |
210 |
joinchar = "&"
|
211 |
|
212 |
return "%s%s%s" % (url, joinchar, urllib.urlencode(attrs)) |
213 |
|
214 |
|
215 |
EXTRA_CONTENT_MAP = { |
216 |
'confirm_text': '<textarea name="reason"></textarea>' |
217 |
} |
218 |
|
219 |
CONFIRM_LINK_PROMPT_MAP = { |
220 |
'project_modification_cancel': _('Are you sure you want to dismiss this ' |
221 |
'project ?'),
|
222 |
'project_app_cancel': _('Are you sure you want to cancel this project ?'), |
223 |
'project_app_approve': _('Are you sure you want to approve this ' |
224 |
'project ?'),
|
225 |
'project_app_deny': _('Are you sure you want to deny this project ? ' |
226 |
'<br /><br />You '
|
227 |
'may optionally provide denial reason in the '
|
228 |
'following field: <br /><br /><textarea '
|
229 |
'class="deny_reason" name="reason"></textarea>'),
|
230 |
'project_app_dismiss': _('Are you sure you want to dismiss this ' |
231 |
'project ?'),
|
232 |
'project_join': _('Are you sure you want to join this project ?'), |
233 |
'project_leave': _('Are you sure you want to leave from the project ?'), |
234 |
} |
235 |
|
236 |
|
237 |
@register.tag(name="confirm_link") |
238 |
@basictag(takes_context=True) |
239 |
def confirm_link(context, title, prompt='', url=None, urlarg=None, |
240 |
extracontent='',
|
241 |
confirm_prompt=None,
|
242 |
inline=True,
|
243 |
template="im/table_rich_link_column.html"):
|
244 |
|
245 |
urlargs = None
|
246 |
if urlarg:
|
247 |
urlargs = (urlarg,) |
248 |
|
249 |
if CONFIRM_LINK_PROMPT_MAP.get(prompt, None): |
250 |
prompt = mark_safe(CONFIRM_LINK_PROMPT_MAP.get(prompt)) |
251 |
|
252 |
url = reverse(url, args=urlargs) |
253 |
title = _(title) |
254 |
tpl_context = RequestContext(context.get('request'))
|
255 |
tpl_context.update({ |
256 |
'col': {
|
257 |
'method': 'POST', |
258 |
'cancel_prompt': 'CANCEL', |
259 |
'confirm_prompt': confirm_prompt or title |
260 |
}, |
261 |
'inline': inline,
|
262 |
'url': url,
|
263 |
'action': title,
|
264 |
'prompt': prompt,
|
265 |
'extra_form_content': EXTRA_CONTENT_MAP.get(extracontent, ''), |
266 |
'confirm': True |
267 |
}) |
268 |
|
269 |
content = render_to_string(template, tpl_context) |
270 |
return content
|
271 |
|
272 |
|
273 |
class VerbatimNode(template.Node): |
274 |
|
275 |
def __init__(self, text): |
276 |
self.text = text
|
277 |
|
278 |
def render(self, context): |
279 |
return self.text |
280 |
|
281 |
|
282 |
@register.tag
|
283 |
def verbatim(parser, token): |
284 |
text = [] |
285 |
while 1: |
286 |
token = parser.tokens.pop(0)
|
287 |
if token.contents == 'endverbatim': |
288 |
break
|
289 |
if token.token_type == template.TOKEN_VAR:
|
290 |
text.append('{{')
|
291 |
elif token.token_type == template.TOKEN_BLOCK:
|
292 |
text.append('{%')
|
293 |
text.append(token.contents) |
294 |
if token.token_type == template.TOKEN_VAR:
|
295 |
text.append('}}')
|
296 |
elif token.token_type == template.TOKEN_BLOCK:
|
297 |
text.append('%}')
|
298 |
return VerbatimNode(''.join(text)) |