Source

django-lfc / lfc / templatetags / lfc_tags.py

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# python imports
import datetime

# django import
from django import template
from django.conf import settings
from django.contrib.auth.models import User, AnonymousUser
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404
from django.template import Node, TemplateSyntaxError
from django.template.loader import render_to_string
from django.utils import translation
from django.utils.translation import ugettext_lazy as _

# contact_form imports
from contact_form.forms import ContactForm

# tagging imports
from tagging.managers import ModelTaggedItemManager

# feedparser imports
import feedparser

# permissions imports
import permissions.utils

# lfc imports
import lfc.utils
from lfc.utils import registration
from lfc.models import BaseContent
from lfc.models import Page

register = template.Library()

@register.inclusion_tag('lfc/manage/templates.html', takes_context=True)
def templates(context):
    """Displays a selection box to select a available template for context
    on the fly.
    """
    lfc_context = context.get("lfc_context")
    request = context.get("request")

    if lfc_context is None:
        return {
            "display" : False,
        }

    templates = registration.get_templates(lfc_context)
    if templates and len(templates) > 1:
        display = True
        template = lfc_context.template or registration.get_default_template(lfc_context)
        if template:
            template_id = template.id
        else:
            template_id = None
    else:
        template_id = None
        display = False

    return {
        "display" : display,
        "templates" : templates,
        "obj_id" : lfc_context.id,
        "current_template" : template_id
    }

class LanguagesNode(Node):
    """
    """
    def render(self, context):
        lfc_context = context.get("lfc_context")
        request = context.get("request")

        # CACHE
        if lfc_context:
            cache_key = "languages-%s-%s" % (lfc_context.id, request.user.id)
        else:
            cache_key = "languages-none-%s" % request.user.id

        languages = cache.get(cache_key)

        if languages is None:
            languages = []
            for language in settings.LANGUAGES:
                if lfc_context is None:
                    is_available = True
                elif lfc_context.has_language(request, language[0]):
                    is_available = True
                else:
                    is_available = False

                languages.append({
                    "code" : language[0],
                    "name" : language[1],
                    "is_available" : is_available,
                })

        # Set cache
        cache.set(cache_key, languages)

        context["lfc_languages"] = languages
        return ''

def do_languages(parser, token):
    """Tag to put the contact form into context.
    """
    bits = token.contents.split()
    len_bits = len(bits)
    if len_bits != 1:
        raise TemplateSyntaxError(_('%s tag needs no argument') % bits[0])

    return LanguagesNode()

register.tag('lfc_languages', do_languages)

class ContactFormNode(Node):
    """Tag to put the contact form into context.
    """
    def render(self, context):
        request = context.get("request")
        if request.method == "POST":
            contact_form = ContactForm(data=request.POST, request=request)
        else:
            contact_form = ContactForm(request=request)

        context["form"] = contact_form
        return ''

def do_contact_form(parser, token):
    """Tag to put the contact form into context.
    """
    bits = token.contents.split()
    len_bits = len(bits)
    if len_bits != 1:
        raise TemplateSyntaxError(_('%s tag needs no argument') % bits[0])

    return ContactFormNode()

register.tag('contact_form', do_contact_form)

@register.inclusion_tag('lfc/tags/tabs.html', takes_context=True)
def tabs(context):
    """Returns the top level pages as tabs (aka horizontal menu bar).
    """
    request = context.get("request")
    language = context.get("LANGUAGE_CODE")

    lfc_context = context.get("lfc_context")
    
    # CACHE
    if lfc_context:
        cache_key = "tabs-%s-%s-%s" % (lfc_context.content_type, lfc_context.id, request.user.id)
    else:
        cache_key = "tabs-portal"

    tabs = cache.get(cache_key)

    if tabs is None:
        tl_objs = lfc.utils.get_content_objects(
            request,
            language__in=(language, "0"),
            parent = None,
            exclude_from_navigation=False,
        )

        if lfc_context is None:
            current_pages = []
        else:
            current_pages = [lfc_context]
            current_pages.extend(lfc_context.get_ancestors())

        tabs = []
        for obj in tl_objs:
            obj.current = obj in current_pages
            tabs.append(obj)

        cache.set(cache_key, tabs)

    return {
        "language" : language,
        "tabs" : tabs,
        "portal" : lfc.utils.get_portal(),
    }

@register.inclusion_tag('lfc/tags/scrollable.html', takes_context=True)
def scrollable(context, tags=None, title=False, text=True, limit=5):
    """Displays objects with given tabs as scrollable
    """
    items = lfc.utils.get_content_object(request)

    if tags:
        items = ModelTaggedItemManager().with_all(tags, items)

    return {
        "items" : items,
        "title" : title,
        "text" : text,
    }

@register.inclusion_tag('lfc/tags/rss.html', takes_context=True)
def rss(context, url, limit=5):
    """An inclusion tag which displays an rss feed.
    """
    feed = feedparser.parse(url)

    try:
        name = feed["feed"]["link"].split("/")[-1]
    except (KeyError, IndexError, AttributeError):
        return {
            "entries" : [],
            "link" : "",
            "LANGUAGE_CODE" : "",
        }

    entries = []
    for entry in feed.entries[0:limit]:
        summary = entry.summary.replace("%s: " % name, "")

        entries.append({
            "title" : entry.title,
            "summary" : summary,
            "date" : datetime.datetime(*entry["updated_parsed"][0:6])
        })

    return {
        "entries" : entries,
        "LANGUAGE_CODE" : context.get("LANGUAGE_CODE"),
        "link" : feed["feed"]["link"],
    }

@register.inclusion_tag('lfc/tags/navigation.html', takes_context=True)
def navigation(context, start_level=1, expand_level=0):
    """Tag to render a navigation tree. This is also reused by the navigation
    portlet.
    """
    request = context.get("request")
    obj = request.META.get("lfc_context")

    language = translation.get_language()

    temp = lfc.utils.get_content_objects(request,
        parent = None,
        language__in = (language, "0"),
        exclude_from_navigation=False)

    # Add portal's standard to current_objs
    if obj is None:
        current_objs = []
        standard = lfc.utils.get_portal().standard
        if standard:
            if language != standard.language:
                standard = standard.get_translation(request, language)
            if standard:
                current_objs.append(standard.get_content_object())
    else:
        current_objs = [obj]
        current_objs.extend(obj.get_ancestors())

    objs = []
    for obj in temp:
        if obj in current_objs:
            children = _navigation_children(request, current_objs, obj, start_level, expand_level)
            is_current = True
        elif expand_level >= 1 and start_level <= 1:
            children = _navigation_children(request, current_objs, obj, start_level, expand_level)
            is_current = False
        else:
            children = ""
            is_current = False

        objs.append({
            "id" : obj.id,
            "slug" : obj.slug,
            "title" : obj.title,
            "url" : obj.get_absolute_url(),
            "is_current" : is_current,
            "children" : children,
            "level" : 1
        })

    return {
        "objs" : objs,
        "show_level" : start_level==1
    }

def _navigation_children(request, current_objs, obj, start_level, expand_level, level=2):
    """Renders the children of given object as sub navigation tree.
    """
    obj = obj
    temp = obj.get_children(request, exclude_from_navigation = False,
        language__in = (translation.get_language(), "0"),
    )

    objs = []
    for obj in temp:
        if obj in current_objs:
            children = _navigation_children(request, current_objs, obj, start_level, expand_level, level=level+1)
            is_current = True
        elif level <= expand_level and level >= start_level:
            children = _navigation_children(request, current_objs, obj, start_level, expand_level, level=level+1)
            is_current = False
        else:
            children = ""
            is_current = False

        objs.append({
            "id" : obj.id,
            "slug" : obj.slug,
            "title" : obj.title,
            "url" : obj.get_absolute_url(),
            "is_current" : is_current,
            "children" : children,
            "level" : level,
        })

    result = render_to_string("lfc/tags/navigation_children.html", {
        "objs" : objs,
        "show_level" : level >= start_level,
    })

    return result

@register.inclusion_tag('lfc/tags/breadcrumbs.html', takes_context=True)
def breadcrumbs(context):
    """Displays breadcrumbs.
    """
    obj = context.get("lfc_context")
    if obj is None:
        return {
            "obj" : None,
            "objs" : []
        }

    objs = []

    temp = obj
    while temp is not None:
        objs.insert(0, temp)
        temp = temp.parent

    return {
        "obj" : obj,
        "objs" : objs,
    }

@register.inclusion_tag('lfc/tags/page.html', takes_context=True)
def page(context, slug, part):
    """Displays the a part (title/text) of the page with passes slug.
    """
    request = context.get("request")
    page = lfc.utils.traverse_object(request, slug)

    if page:
        page = page.get_content_object()

    return { "page" : page, "part": part }

@register.inclusion_tag('lfc/tags/objects.html', takes_context=True)
def objects_by_slug(context, slug, limit=5, title=True, text=False):
    """Display all sub objects of the object with given slug
    """
    request = context.get("request")
    try:
        obj = lfc.utils.traverse_object(request, slug)
    except Http404:
        return { "objs" : [] }

    objs = obj.children.all().order_by("-publication_date")[:limit]

    result = []
    for obj in objs:
        result.append(obj.get_content_object())

    return {
        "objs" : result,
        "title" : title,
        "text" : text,
    }

@register.inclusion_tag('lfc/tags/previous_next.html')
def previous_next_by_date(obj):
    """Displays previous/links by creation date for the given object.
    """
    try:
        previous = obj.get_previous_by_creation_date(parent=obj.parent)
    except ObjectDoesNotExist:
        previous = None

    try:
        next = obj.get_next_by_creation_date(parent=obj.parent)
    except ObjectDoesNotExist:
        next = None

    return {
        "previous" : previous,
        "next" : next,
    }

@register.inclusion_tag('lfc/tags/previous_next.html', takes_context=True)
def previous_next_by_position(context, obj):
    """Displays previous/links by position for the given object.
    """
    request = context.get("request")
    siblings = [o.get_content_object() for o in obj.parent.children.all()]
    current_position = siblings.index(obj)
    next_position = current_position + 1
    previous_position = current_position - 1

    if previous_position < 0:
        previous = None
    else:
        try:
            previous = siblings[previous_position]
        except IndexError:
            previous = None

    try:
        next = siblings[next_position]
    except IndexError:
        next = None

    return {
        "previous" : previous,
        "next" : next,
    }

from django.forms import ChoiceField, FileField, CharField, Textarea

@register.filter(name='field_value')
def field_value(field):
    """ Returns the value for this BoundField, as rendered in widgets.
    """
    if field.form.is_bound:
        if isinstance(field.field, FileField) and field.data is None:
            val = field.form.initial.get(field.name, field.field.initial)
        else:
            val = field.data
    else:
        val = field.form.initial.get(field.name, field.field.initial)
        if callable(val):
            val = val()
    if val is None:
        val = ''
    return val

@register.filter(name='display_value')
def display_value(field):
    """
    Returns the displayed value for this BoundField, as rendered in widgets.
    """
    value = field_value(field)
    if isinstance(field.field, CharField) and isinstance(field.field.widget, Textarea):
        value = """<div class="%s field-wrapper">%s</div>""" % (field.name, value)

    if isinstance(field.field, ChoiceField):
        for (val, desc) in field.field.choices:
            if val == value:
                return desc
    return value

class PermissionComparisonNode(template.Node):
    """Implements a node to provide an if current user has passed permission
    for current object tag.

    Slightly different from permission's default ifhasperm tag to use the
    has_permission method of lfc.
    """
    @classmethod
    def handle_token(cls, parser, token):
        bits = token.contents.split()
        if len(bits) not in (2, 3):
            raise template.TemplateSyntaxError(
                "'%s' tag takes one argument" % bits[0])
        end_tag = 'endifhasperm'
        nodelist_true = parser.parse(('else', end_tag))
        token = parser.next_token()
        if token.contents == 'else': # there is an 'else' clause in the tag
            nodelist_false = parser.parse((end_tag,))
            parser.delete_first_token()
        else:
            nodelist_false = ""

        return cls(bits[1], nodelist_true, nodelist_false)

    def __init__(self, permission, nodelist_true, nodelist_false):
        self.permission = permission
        self.nodelist_true = nodelist_true
        self.nodelist_false = nodelist_false

    def render(self, context):
        obj = context.get("obj")
        request = context.get("request")
        if obj.has_permission(request.user, self.permission):
            return self.nodelist_true.render(context)
        else:
            try:
                return self.nodelist_false.render(context)
            except AttributeError:
                return ""

@register.tag
def ifhasperm(parser, token):
    """This function provides functionality for the 'ifhasperm' template tag.
    """
    return PermissionComparisonNode.handle_token(parser, token)

class PortalPermissionComparisonNode(template.Node):
    """Implements a node to provide an if current user has passed permission
    for current object tag.

    Slightly different from permission's default ifhasperm tag to use the
    has_permission method of lfc.
    """
    @classmethod
    def handle_token(cls, parser, token):
        bits = token.contents.split()
        if len(bits) not in (2, 3):
            raise template.TemplateSyntaxError(
                "'%s' tag takes one argument" % bits[0])
        end_tag = 'endifportalhasperm'
        nodelist_true = parser.parse(('else', end_tag))
        token = parser.next_token()
        if token.contents == 'else': # there is an 'else' clause in the tag
            nodelist_false = parser.parse((end_tag,))
            parser.delete_first_token()
        else:
            nodelist_false = ""

        return cls(bits[1], nodelist_true, nodelist_false)

    def __init__(self, permission, nodelist_true, nodelist_false):
        self.permission = permission
        self.nodelist_true = nodelist_true
        self.nodelist_false = nodelist_false

    def render(self, context):
        obj = lfc.utils.get_portal()
        request = context.get("request")
        if obj.has_permission(request.user, self.permission):
            return self.nodelist_true.render(context)
        else:
            try:
                return self.nodelist_false.render(context)
            except AttributeError:
                return ""

@register.tag
def ifportalhasperm(parser, token):
    """This function provides functionality for the 'ifportalhasperm' template tag.
    """
    return PortalPermissionComparisonNode.handle_token(parser, token)