Merge branch 'master' into gilbert
[philo.git] / validators.py
index 106db8b..5ae9409 100644 (file)
@@ -1,15 +1,18 @@
 from django.utils.translation import ugettext_lazy as _
 from django.core.validators import RegexValidator
 from django.core.exceptions import ValidationError
+from django.template import Template, Parser, Lexer, TOKEN_BLOCK, TOKEN_VAR, TemplateSyntaxError
 from django.utils import simplejson as json
+from django.utils.html import escape, mark_safe
 import re
+from philo.utils import LOADED_TEMPLATE_ATTR
 
 
-LOADED_TEMPLATE_ATTR = '_philo_loaded_template'
 INSECURE_TAGS = (
        'load',
        'extends',
        'include',
+       'debug',
 )
 
 
@@ -43,11 +46,8 @@ class URLLinkValidator(RegexValidator):
 def json_validator(value):
        try:
                json.loads(value)
-       except:
-               raise ValidationError(u'\'%s\' is not valid JSON' % value)
-
-
-from django.template import Template, Parser, Lexer, TOKEN_BLOCK
+       except Exception, e:
+               raise ValidationError(u'JSON decode error: %s' % e)
 
 
 class TemplateValidationParser(Parser):
@@ -59,7 +59,7 @@ class TemplateValidationParser(Parser):
                if secure:
                        disallow |= set(INSECURE_TAGS)
                
-               self.allow, self.disallow = allow, disallow
+               self.allow, self.disallow, self.secure = allow, disallow, secure
        
        def parse(self, parse_until=None):
                if parse_until is None:
@@ -112,7 +112,19 @@ class TemplateValidationParser(Parser):
                return nodelist
        
        def disallowed_tag(self, command):
-               raise ValidationError("Tag not allowed: %s" % command)
+               if self.secure and command in INSECURE_TAGS:
+                       raise ValidationError('Tag "%s" is not permitted for security reasons.' % command)
+               raise ValidationError('Tag "%s" is not permitted here.' % command)
+
+
+def linebreak_iter(template_source):
+       # Cribbed from django/views/debug.py
+       yield 0
+       p = template_source.find('\n')
+       while p >= 0:
+               yield p+1
+               p = template_source.find('\n', p+1)
+       yield len(template_source) + 1
 
 
 class TemplateValidator(object): 
@@ -127,6 +139,14 @@ class TemplateValidator(object):
                except ValidationError:
                        raise
                except Exception, e:
+                       if hasattr(e, 'source') and isinstance(e, TemplateSyntaxError):
+                               origin, (start, end) = e.source
+                               template_source = origin.reload()
+                               upto = 0
+                               for num, next in enumerate(linebreak_iter(template_source)):
+                                       if start >= upto and end <= next:
+                                               raise ValidationError(mark_safe("Template code invalid: \"%s\" (%s:%d).<br />%s" % (escape(template_source[start:end]), origin.loadname, num, e)))
+                                       upto = next
                        raise ValidationError("Template code invalid. Error was: %s: %s" % (e.__class__.__name__, e))
        
        def validate_template(self, template_string):