Update support for wrregion and wrregioncache.
[philipp/winterrodeln/wrpylib.git] / wrpylib / wrvalidators.py
index bad2e857ea1ce12616255413df2c0f817a6bba6e..d721da0178722971bf2b13048aa71628dea46c27 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.6
+#!/usr/bin/python2.7
 # -*- coding: iso-8859-15 -*-
 # $Id$
 # $HeadURL$
 # -*- coding: iso-8859-15 -*-
 # $Id$
 # $HeadURL$
@@ -6,12 +6,12 @@
 of properties used in the "Rodelbahnbox" and "Gasthausbox".
 The "to_python" method has to get a unicode argument.
 """
 of properties used in the "Rodelbahnbox" and "Gasthausbox".
 The "to_python" method has to get a unicode argument.
 """
-import formencode
-import formencode.national
 import datetime
 import re
 import xml.dom.minidom as minidom
 from xml.parsers.expat import ExpatError
 import datetime
 import re
 import xml.dom.minidom as minidom
 from xml.parsers.expat import ExpatError
+import formencode
+import formencode.national
 
 
 class NoneValidator(formencode.FancyValidator):
 
 
 class NoneValidator(formencode.FancyValidator):
@@ -126,7 +126,7 @@ class Loop(formencode.FancyValidator):
     
     def from_python(self, value):
         # we don't call self.validator.to_python(self.validator.from_python(value))
     
     def from_python(self, value):
         # we don't call self.validator.to_python(self.validator.from_python(value))
-        # here because our to_python implementation basically leaves the input untouches
+        # here because our to_python implementation basically leaves the input untouched
         # and so should from_python do.
         return self.validator.from_python(self.validator.to_python(value))
 
         # and so should from_python do.
         return self.validator.from_python(self.validator.to_python(value))
 
@@ -149,7 +149,8 @@ class DictValidator(formencode.FancyValidator):
     
     def from_python(self, value):
         for k, v in self.dict.iteritems():
     
     def from_python(self, value):
         for k, v in self.dict.iteritems():
-            if type(v) == type(value) and v == value: return k
+            if v == value:
+                return k
         raise formencode.Invalid('Invalid value', value, None)
 
 
         raise formencode.Invalid('Invalid value', value, None)
 
 
@@ -185,10 +186,14 @@ class GermanTristateFloat(GermanTristateTuple):
 
 
 class ValueComment(formencode.FancyValidator):
 
 
 class ValueComment(formencode.FancyValidator):
-    """Converts value with a potentially optional comment to a python tuple:
-    u''                <=> (None, None)
-    u'value'           <=> (u'value', None)
-    u'value (comment)' <=> (u'value', u'comment')"""
+    """Converts value with a potentially optional comment to a python tuple. If a comment is present, the
+    closing bracket has to be the rightmost character.
+    u''                                 <=> (None, None)
+    u'value'                            <=> (u'value', None)
+    u'value (comment)'                  <=> (u'value', u'comment')
+    u'[[link (linkcomment)]]'           <=> (u'[[link (linkcomment)]]', None)
+    u'[[link (linkcomment)]] (comment)' <=> (u'[[link (linkcomment)]]', comment)
+    """
     def __init__(self, value_validator=UnicodeNone(), comment_validator=UnicodeNone(), comment_is_optional=True):
         self.value_validator = value_validator
         self.comment_validator = comment_validator
     def __init__(self, value_validator=UnicodeNone(), comment_validator=UnicodeNone(), comment_is_optional=True):
         self.value_validator = value_validator
         self.comment_validator = comment_validator
@@ -200,16 +205,16 @@ class ValueComment(formencode.FancyValidator):
             v = value
             c = value
         else:
             v = value
             c = value
         else:
-            left = value.find('(')
             right = value.rfind(')')
             right = value.rfind(')')
-            if left < 0 and right < 0:
+            if right+1 != len(value):
                 if not self.comment_is_optional: raise formencode.Invalid(u'Mandatory comment not present', value, None)
                 v = value
                 c = u''
                 if not self.comment_is_optional: raise formencode.Invalid(u'Mandatory comment not present', value, None)
                 v = value
                 c = u''
-            elif left >= 0 and right >= 0 and left < right:
+            else:
+                left = value.rfind('(')
+                if left < 0: raise formencode.Invalid(u'Invalid format', value, None)
                 v = value[:left].strip()
                 c = value[left+1:right].strip()
                 v = value[:left].strip()
                 c = value[left+1:right].strip()
-            else: raise formencode.Invalid(u'Invalid format', value, None)
         return self.value_validator.to_python(v), self.comment_validator.to_python(c)
 
     def from_python(self, value):
         return self.value_validator.to_python(v), self.comment_validator.to_python(c)
 
     def from_python(self, value):
@@ -594,6 +599,38 @@ class PhoneCommentListNeinLoopNone(NoneValidator):
         NoneValidator.__init__(self, NeinValidator(Loop(ValueCommentList(PhoneNumber(default_cc=43), comments_are_optional=comments_are_optional))))
 
 
         NoneValidator.__init__(self, NeinValidator(Loop(ValueCommentList(PhoneNumber(default_cc=43), comments_are_optional=comments_are_optional))))
 
 
+class MaskedEmail(formencode.FancyValidator):
+    """A masked email address as defined here is an email address that has the `@` character replacted by the text `(at)`.
+    So instead of `abd.def@example.com` it would be `abc.def(at)example.com`.
+    This validator takes either a normal or a masked email address in it's to_python method and returns the normal email address as well
+    as a bool indicating whether the email address was masked.
+    u''                       <=> (None, None)
+    u'abc.def@example.com'    <=> (u'abc.def@example.com', False)
+    u'abc.def(at)example.com' <=> (u'abc.def@example.com', True)
+    
+    """
+    def __init__(self, *args, **kw):
+        if not kw.has_key('strip'): kw['strip'] = True
+        if not kw.has_key('not_empty'): kw['not_empty'] = False
+        if not kw.has_key('if_empty'): kw['if_empty'] = (None, None)
+        self.at = '(at)'
+        formencode.FancyValidator.__init__(self, *args, **kw)
+
+    def _to_python(self, value, state):
+        email = value.replace(self.at, '@')
+        masked = value != email
+        val_email = formencode.validators.Email()
+        return val_email.to_python(email), masked
+
+    def _from_python(self, value, state):
+        email, masked = value
+        if email is None: return u''
+        val_email = formencode.validators.Email()
+        email = val_email.from_python(email)
+        if masked: email = email.replace('@', self.at)
+        return email
+
+
 class EmailCommentListNeinLoopNone(NoneValidator):
     """Converts a semicolon-separated list of email addresses with optional comments to itself.
     The special value of u'Nein' indicates that there are no email addresses.
 class EmailCommentListNeinLoopNone(NoneValidator):
     """Converts a semicolon-separated list of email addresses with optional comments to itself.
     The special value of u'Nein' indicates that there are no email addresses.
@@ -602,9 +639,12 @@ class EmailCommentListNeinLoopNone(NoneValidator):
     u'Nein'                                               <=> u'Nein'
     u'first@example.com'                                  <=> u'first@example.com'
     u'first@example.com (Nur Winter); second@example.com' <=> u'first@example.com (Nur Winter); second@example.com'
     u'Nein'                                               <=> u'Nein'
     u'first@example.com'                                  <=> u'first@example.com'
     u'first@example.com (Nur Winter); second@example.com' <=> u'first@example.com (Nur Winter); second@example.com'
+
+    If the parameter allow_masked_email is true, the following gives no error:
+    u'abc.def(at)example.com (comment)'                   <=> u'abc.def(at)example.com (comment)'
     """
     """
-    def __init__(self):
-        NoneValidator.__init__(self, NeinValidator(Loop(ValueCommentList(formencode.validators.Email()))))
+    def __init__(self, allow_masked_email=False):
+        NoneValidator.__init__(self, NeinValidator(Loop(ValueCommentList(MaskedEmail() if allow_masked_email else formencode.validators.Email()))))
 
 
 class WikiPage(formencode.FancyValidator):
 
 
 class WikiPage(formencode.FancyValidator):