Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / templatetags / astakos_tags.py @ 8fb8d0cf

History | View | Annotate | Download (10.4 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 synnefo_branding.utils 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
                    m = "Any tag function decorated with takes_context=True " \
105
                        "must have a first argument of 'context'"
106
                    raise TemplateSyntaxError(m)
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
                    m = "%r tag takes %d arguments." % (tag_name, min_args)
113
                    raise TemplateSyntaxError(m)
114
                else:
115
                    m = "%r tag takes %d to %d arguments, got %d." % \
116
                        (tag_name, min_args, max_args, len(bits))
117
                    raise TemplateSyntaxError(m)
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(
184
            resource__name=rname).member_capacity
185
    except Exception, e:
186
        r = ''
187
    return r
188

    
189

    
190
@register.tag(name="provider_login_url")
191
@basictag(takes_context=True)
192
def provider_login_url(context, provider, from_login=False):
193
    request = context['request'].REQUEST
194
    next = request.get('next', None)
195
    code = request.get('code', None)
196
    key = request.get('key', None)
197

    
198
    attrs = {}
199
    if next:
200
        attrs['next'] = next
201
    if code:
202
        attrs['code'] = code
203
    if key:
204
        attrs['key'] = key
205
    if from_login:
206
        attrs['from_login'] = 1
207

    
208
    url = provider.urls.get('login')
209

    
210
    joinchar = "?"
211
    if "?" in url:
212
        joinchar = "&"
213

    
214
    return "%s%s%s" % (url, joinchar, urllib.urlencode(attrs))
215

    
216

    
217
EXTRA_CONTENT_MAP = {
218
    'confirm_text': '<textarea name="reason"></textarea>'
219
}
220

    
221
CONFIRM_LINK_PROMPT_MAP = {
222
    'project_modification_cancel': _('Are you sure you want to dismiss this '
223
                                     'project ?'),
224
    'project_app_cancel': _('Are you sure you want to cancel this project ?'),
225
    'project_app_approve': _('Are you sure you want to approve this '
226
                             'project ?'),
227
    'project_app_deny': _('Are you sure you want to deny this project ? '
228
                          '<br /><br />You '
229
                          'may optionally provide denial reason in the '
230
                          'following field: <br /><br /><textarea '
231
                          'class="deny_reason" name="reason"></textarea>'),
232
    'project_app_dismiss': _('Are you sure you want to dismiss this '
233
                             'project ?'),
234
    'project_join': _('Are you sure you want to join this project ?'),
235
    'project_leave': _('Are you sure you want to leave from the project ?'),
236
}
237

    
238

    
239
@register.tag(name="confirm_link")
240
@basictag(takes_context=True)
241
def confirm_link(context, title, prompt='', url=None, urlarg=None,
242
                 extracontent='',
243
                 confirm_prompt=None,
244
                 inline=True,
245
                 cls='',
246
                 template="im/table_rich_link_column.html"):
247

    
248
    urlargs = None
249
    if urlarg:
250
        if isinstance(urlarg, basestring) and "," in urlarg:
251
            args = urlarg.split(",")
252
            for index, arg in enumerate(args):
253
                if context.get(arg, None) is not None:
254
                    args[index] = context.get(arg)
255
            urlargs = args
256
        else:
257
            urlargs = (urlarg,)
258

    
259
    if CONFIRM_LINK_PROMPT_MAP.get(prompt, None):
260
        prompt = mark_safe(CONFIRM_LINK_PROMPT_MAP.get(prompt))
261

    
262
    if url:
263
        url = reverse(url, args=urlargs)
264
    else:
265
        url = None
266

    
267
    title = _(title)
268
    tpl_context = RequestContext(context.get('request'))
269
    tpl_context.update({
270
        'col': {
271
            'method': 'POST',
272
            'cancel_prompt': 'CANCEL',
273
            'confirm_prompt': confirm_prompt or title
274
        },
275
        'inline': inline,
276
        'url': url,
277
        'action': title,
278
        'cls': cls,
279
        'prompt': prompt,
280
        'extra_form_content': EXTRA_CONTENT_MAP.get(extracontent, ''),
281
        'confirm': True
282
    })
283

    
284
    content = render_to_string(template, tpl_context)
285
    return content
286

    
287

    
288
@register.simple_tag
289
def substract(arg1, arg2):
290
    return arg1 - arg2
291

    
292

    
293
class VerbatimNode(template.Node):
294

    
295
    def __init__(self, text):
296
        self.text = text
297

    
298
    def render(self, context):
299
        return self.text
300

    
301

    
302
@register.tag
303
def verbatim(parser, token):
304
    text = []
305
    while 1:
306
        token = parser.tokens.pop(0)
307
        if token.contents == 'endverbatim':
308
            break
309
        if token.token_type == template.TOKEN_VAR:
310
            text.append('{{')
311
        elif token.token_type == template.TOKEN_BLOCK:
312
            text.append('{%')
313
        text.append(token.contents)
314
        if token.token_type == template.TOKEN_VAR:
315
            text.append('}}')
316
        elif token.token_type == template.TOKEN_BLOCK:
317
            text.append('%}')
318
    return VerbatimNode(''.join(text))