Django 1.11 compatibility fixes.
[django-ssify.git] / ssify / decorators.py
index 9b67c25..1e2d62a 100644 (file)
@@ -1,14 +1,31 @@
+# -*- coding: utf-8 -*-
+# This file is part of django-ssify, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See README.md for more information.
+#
+"""
+Defines decorators for use in ssify-enabled projects.
+"""
+from __future__ import unicode_literals
 import functools
 from inspect import getargspec
 import warnings
-from django.template.base import parse_bits
+from django.conf import settings
+from django.http import Http404
+try:
+    # Django 1.9
+    from django.template.library import parse_bits
+except ImportError:
+    from django.template.base import parse_bits
+
 from django.utils.translation import get_language, activate
-from .store import cache_include
+from .cache import cache_include, DEFAULT_TIMEOUT
 from . import exceptions
 from .variables import SsiVariable
 
 
-def ssi_included(view=None, use_lang=True, get_ssi_vars=None):
+def ssi_included(view=None, use_lang=True,
+        timeout=DEFAULT_TIMEOUT, version=None,
+        get_ssi_vars=None, patch_response=None):
     """
     Marks a view to be used as a snippet to be included with SSI.
 
@@ -29,20 +46,26 @@ def ssi_included(view=None, use_lang=True, get_ssi_vars=None):
                     lang = kwargs.pop('lang')
                 except KeyError:
                     raise exceptions.NoLangFieldError(request)
+                if lang not in [language[0] for language in settings.LANGUAGES]:
+                    raise Http404
                 current_lang = get_language()
                 activate(lang)
+                request.LANGUAGE_CODE = lang
             response = view(request, *args, **kwargs)
             if use_lang:
                 activate(current_lang)
             if response.status_code == 200:
+                # We don't want this view to be cached in
+                # UpdateCacheMiddleware. We'll just cache the contents
+                # ourselves, and point the webserver to use this cache.
                 request._cache_update_cache = False
 
                 def _check_included_vars(response):
-                    used_vars = request.ssi_vars_needed
+                    used_vars = getattr(request, 'ssi_vars_needed', {})
                     if get_ssi_vars:
                         # Remove the ssi vars that should be provided
                         # by the including view.
-                        pass_vars = set(get_ssi_vars(*args, **kwargs))
+                        pass_vars = get_ssi_vars(*args, **kwargs)
 
                         for var in pass_vars:
                             if not isinstance(var, SsiVariable):
@@ -60,7 +83,8 @@ def ssi_included(view=None, use_lang=True, get_ssi_vars=None):
 
                     # Don't use default django response caching for this view,
                     # just save the contents instead.
-                    cache_include(request.path, response.content)
+                    cache_include(request.path, response.content,
+                        timeout=timeout, version=version)
 
                 if hasattr(response, 'render') and callable(response.render):
                     response.add_post_render_callback(_check_included_vars)
@@ -72,13 +96,23 @@ def ssi_included(view=None, use_lang=True, get_ssi_vars=None):
         # Remember get_ssi_vars so that in can be computed from args/kwargs
         # by including view.
         new_view.get_ssi_vars = get_ssi_vars
+        new_view.ssi_patch_response = patch_response
         return new_view
     return dec(view) if view else dec
 
 
-def ssi_variable(register, vary=None, name=None):
+def ssi_variable(register, name=None, patch_response=None):
+    """
+    Creates a template tag representing an SSI variable from a function.
+
+    The function must take 'request' as its first argument.
+    It may take other arguments, which should be provided when using
+    the template tag.
+
+    """
     # Cache control?
     def dec(func):
+
         # Find own path.
         function_name = (name or
                          getattr(func, '_decorated_function', func).__name__)
@@ -121,7 +155,7 @@ def ssi_variable(register, vary=None, name=None):
                                       ['context'] + params[1:], varargs, varkw,
                                       defaults, takes_context=True,
                                       name=function_name)
-            return SsiVariableNode(tagpath, args, kwargs, vary, asvar)
+            return SsiVariableNode(tagpath, args, kwargs, patch_response, asvar)
         _ssi_var_tag.get_value = func
         #return _ssi_var_tag
         return func