1 # -*- coding: utf-8 -*-
 
   2 # This file is part of django-ssify, licensed under GNU Affero GPLv3 or later.
 
   3 # Copyright © Fundacja Nowoczesna Polska. See README.md for more information.
 
   5 from __future__ import absolute_import, unicode_literals
 
   6 from django.conf import settings
 
   7 from django.core.urlresolvers import NoReverseMatch, reverse, resolve
 
   8 from django.middleware.csrf import get_token, _sanitize_token, rotate_token
 
   9 from django import template
 
  10 from django.utils.translation import get_language
 
  11 from ssify.decorators import ssi_variable
 
  12 from ssify.utils import ssi_vary_on_cookie
 
  13 from ssify.variables import SsiVariable
 
  16 register = template.Library()
 
  19 @register.simple_tag(takes_context=True)
 
  20 def ssi_include(context, name_, **kwargs):
 
  22     Inserts an SSI include statement for an URL.
 
  24     Works similarly to {% url %}, but only use keyword arguments are
 
  27     In addition to just outputting the SSI include statement, it
 
  28     remembers any request-info the included piece declares as needed.
 
  31     b_kwargs = {'lang': get_language()}
 
  34     for k, value in kwargs.items():
 
  35         if isinstance(value, SsiVariable):
 
  44         url = reverse(name_, kwargs=b_kwargs)
 
  45     except NoReverseMatch:
 
  47         url = reverse(name_, kwargs=b_kwargs)
 
  48     view = resolve(url).func
 
  50     for numstr, orig in subst.items():
 
  51         url = url.replace(numstr, orig.as_var())
 
  52     request = context['request']
 
  54     # Remember the SSI vars the included view says it needs.
 
  55     get_ssi_vars = getattr(view, 'get_ssi_vars', None)
 
  57         pass_vars = get_ssi_vars(**kwargs)
 
  59             if not isinstance(var, SsiVariable):
 
  60                 var = SsiVariable(*var)
 
  61             request.ssi_vars_needed[var.name] = var
 
  63     # Remember the decorators to use on the including view.
 
  64     patch_response = getattr(view, 'ssi_patch_response', None)
 
  66         request.ssi_patch_response.extend(patch_response)
 
  68     # Output the SSI include.
 
  69     return "<!--#include file='%s'-->" % url
 
  72 @ssi_variable(register, patch_response=[ssi_vary_on_cookie])
 
  73 def get_csrf_token(request):
 
  75     CsrfViewMiddleware.process_view is never called for cached
 
  76     responses, and we still need to provide a CSRF token as an
 
  77     ssi variable, we must make sure here that the CSRF token
 
  78     is in request.META['CSRF_COOKIE'].
 
  81     token = get_token(request)
 
  83         # CSRF token is already in place, just return it.
 
  86     # Mimicking CsrfViewMiddleware.process_view.
 
  88         token = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME])
 
  89         request.META['CSRF_COOKIE'] = token
 
  91         # Create new CSRF token.
 
  93         token = get_token(request)
 
  98 @register.inclusion_tag('ssify/csrf_token.html', takes_context=True)
 
  99 def ssi_csrf_token(context):
 
 100     return {'request': context['request']}