0c6fa7831333182755056be8681ef35c04b01a16
[philo.git] / validators.py
1 from django.core.exceptions import ValidationError
2 from django.utils.translation import ugettext_lazy as _
3 from django.core.validators import RegexValidator
4 import re
5
6
7 class TreeParentValidator(object):
8         """
9         constructor takes instance and parent_attr, where instance is the model
10         being validated and parent_attr is where to look on that parent for the
11         comparison.
12         """
13         #message = _("A tree element can't be its own parent.")
14         code = 'invalid'
15         
16         def __init__(self, instance, parent_attr=None, message=None, code=None):
17                 self.instance = instance
18                 self.parent_attr = parent_attr
19                 self.static_message = message
20                 if code is not None:
21                         self.code = code
22         
23         def __call__(self, value):
24                 """
25                 Validates that the self.instance is not found in the parent tree of
26                 the node given as value.
27                 """
28                 parent = value
29                 
30                 while parent:
31                         comparison=self.get_comparison(parent)
32                         if comparison == self.instance:
33                                 # using (self.message, code=self.code) results in the admin interface
34                                 # screwing with the error message and making it be 'Enter a valid value'
35                                 raise ValidationError(self.message)
36                         parent=parent.parent
37         
38         def get_comparison(self, parent):
39                 if self.parent_attr and hasattr(parent, self.parent_attr):
40                         return getattr(parent, self.parent_attr)
41                 
42                 return parent
43         
44         def get_message(self):
45                 return self.static_message or _(u"A %s can't be its own parent." % self.instance.__class__.__name__)
46         message = property(get_message)
47
48
49 class TreePositionValidator(object):
50         code = 'invalid'
51         
52         def __init__(self, parent, slug, obj_class, message=None, code=None):
53                 self.parent = parent
54                 self.slug = slug
55                 self.obj_class = obj_class
56                 self.static_message = message
57                 
58                 if code is not None:
59                         self.code = code
60         
61         def __call__(self, value):
62                 """
63                 Validates that there is no obj of obj_class with the same position
64                 as the compared obj (value) but a different id.
65                 """
66                 if not isinstance(value, self.obj_class):
67                         raise ValidationError(_(u"The value must be an instance of %s." % self.obj_class.__name__))
68                 
69                 try:
70                         obj = self.obj_class.objects.get(slug=self.slug, parent=self.parent)
71                         
72                         if obj.id != value.id:
73                                 raise ValidationError(self.message)
74                 
75                 except self.obj_class.DoesNotExist:
76                         pass
77         
78         def get_message(self):
79                 return self.static_message or _(u"A %s with that path (parent and slug) already exists." % self.obj_class.__name__)
80         message = property(get_message)
81
82
83 class RedirectValidator(RegexValidator):
84         """Based loosely on the URLValidator, but no option to verify_exists"""
85         regex = re.compile(
86                 r'^(?:https?://' # http:// or https://
87                 r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
88                 r'localhost|' #localhost...
89                 r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
90                 r'(?::\d+)?' # optional port
91                 r'(?:/?|[/?#]?\S+)|'
92                 r'[^?#\s]\S*)$',
93                 re.IGNORECASE)
94         message = _(u'Enter a valid absolute or relative redirect target')
95
96
97 class URLLinkValidator(RegexValidator):
98         """Based loosely on the URLValidator, but no option to verify_exists"""
99         regex = re.compile(
100                 r'^(?:https?://' # http:// or https://
101                 r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
102                 r'localhost|' #localhost...
103                 r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
104                 r'(?::\d+)?' # optional port
105                 r'|)' # also allow internal links
106                 r'(?:/?|[/?#]?\S+)$', re.IGNORECASE)
107         message = _(u'Enter a valid absolute or relative redirect target')