]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/commitdiff
Centralized custom validators
authorphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Sun, 29 Mar 2009 14:55:34 +0000 (14:55 +0000)
committerphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Sun, 29 Mar 2009 14:55:34 +0000 (14:55 +0000)
git-svn-id: http://www.winterrodeln.org/svn/servermediawiki/trunk/wradmin@438 7aebc617-e5e2-0310-91dc-80fb5f6d2477

wradmin/wradmin/controllers/bericht.py
wradmin/wradmin/controllers/gasthaus.py
wradmin/wradmin/controllers/rodelbahn.py
wradmin/wradmin/lib/helpers.py
wradmin/wradmin/lib/mediawiki.py
wradmin/wradmin/model/validators.py [new file with mode: 0644]
wradmin/wradmin/tests/test_models.py

index 622c1da745e0a2046882e8729384e9759d8995ea..892509865933b525cf63914dfcb6d52948ed9798 100644 (file)
@@ -12,20 +12,13 @@ import wradmin.model as model
 import sqlalchemy as sa
 import datetime
 import formencode
+import wradmin.model.validators
 
 
 log = logging.getLogger(__name__)
 formencode.api.set_stdtranslation(domain="FormEncode", languages=["de"])
 
 
-class GermanDateTimeConverter(formencode.FancyValidator):
-    def _to_python(self, value, state):
-        "converts datetime strings like '2009-03-22 20:36'"
-        self.assert_string(value, state)
-        try: return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M')
-        except ValueError, e: raise formencode.Invalid(str(e), value, state)
-
-
 class RequireDateIfUserDefined(formencode.validators.FormValidator):
     "requires that date_userdefined is not empty if date_invalid == 'userdefined'"
     def _to_python(self, value_dict, state):
@@ -40,7 +33,7 @@ class ChangeDateInvalidForm(formencode.Schema):
     allow_extra_fields = True
     filter_extra_fields = True
     date_invalid = formencode.validators.OneOf(['no_change', 'tomorrow', 'one_week', 'two_weeks', 'one_week_more', 'end_of_saison', 'now', 'userdefined'], not_empty=True)
-    date_userdefined = GermanDateTimeConverter
+    date_userdefined = wradmin.model.validators.DateTimeNoSecConverter
     chained_validators = [RequireDateIfUserDefined()]
 
 
index 7df806561a552e2e49f2bca746eb0ba8c90b675a..7127ebdde33e1e8600ee1f2daeff6bdde808ed94 100644 (file)
@@ -9,6 +9,7 @@ import webhelpers.paginate as paginate
 from wradmin.lib.base import BaseController, render
 import wradmin.model as model
 import sqlalchemy as sa
+import formencode
 import re
 from wradmin.lib.mediawiki import to_unsigned, to_date, to_geo, to_title, to_tristate, to_email, to_url, to_phone, conv, unicode_e
 
@@ -65,7 +66,7 @@ class GasthausController(BaseController):
             elif key == u'Telefon (Mobil)': inn.mobile_phone = conv(to_phone, value, u'Telefon (Mobil)')
             elif key == u'Rauchfrei': (inn.nonsmoker_area, inn.smoker_area) = conv(to_tristate, value, u'Rauchfrei')
             elif key == u'Aufnahmedatum': inn.creation_date = conv(to_date, value, u'Aufnahmedatum') # '2006-03-15'
-            else: raise Exception(u"Unbekannte Eigenschaft der Gasthausbox: '%s' (mit Wert '%s')" % (key, value))
+            else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Gasthausbox: '%s' (mit Wert '%s')" % (key, value), value, None)
         inn.under_construction = None
         return inn
     
@@ -90,7 +91,7 @@ class GasthausController(BaseController):
                 inn = self._wikipage_to_wrinncache(inn)
                 inn.under_construction = c.execute(select([categorylinks], (categorylinks.c.cl_from==inn.page_id) & (categorylinks.c.cl_to == u'In_Arbeit')).alias('x').count()).fetchone()[0] > 0 # It would be better to do this in the query above
                 model.meta.Session.add(inn)
-            except Exception, e: error_msg = u"Fehler bei Gasthaus '%s': " % inn.page_title + unicode_e(e)
+            except formencode.Invalid, e: error_msg = u"Fehler bei Gasthaus '%s': " % inn.page_title + unicode_e(e)
         model.meta.Session.commit()
         
         # Redirect to result page
index f0de25766492e251b50f906ee0f366ff5449ad2f..a558e04f49202725bfb9f8ed5cca96c7c7754548 100644 (file)
@@ -76,7 +76,7 @@ class RodelbahnController(BaseController):
             elif key == u'Auskunft': sl.information = value
             elif key == u'In Übersichtskarte': sl.show_in_overview = conv(to_bool, value, u'In Übersichtskarte')
             elif key == u'Aufnahmedatum': sl.creation_date = conv(to_date, value, u'Aufnahmedatum') # '2006-03-15'
-            else: raise Exception(u"Unbekannte Eigenschaft der Rodelbahnbox: '%s' (mit Wert '%s')" % (key, value))
+            else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Rodelbahnbox: '%s' (mit Wert '%s')" % (key, value), value, None)
         sl.under_construction = None
         
         # Match Forumlink (e.g. {{Forumlink|68}})
@@ -108,7 +108,7 @@ class RodelbahnController(BaseController):
                 sl = self._wikipage_to_wrsleddingcache(sl)
                 sl.under_construction = c.execute(select([categorylinks], (categorylinks.c.cl_from==sl.page_id) & (categorylinks.c.cl_to == u'In_Arbeit')).alias('x').count()).fetchone()[0] > 0 # It would be better to do this in the query above
                 model.meta.Session.add(sl)
-            except Exception, e: error_msg = u"Fehler bei Rodelbahn '%s': " % sl.page_title + unicode_e(e)
+            except formencode.Invalid, e: error_msg = u"Fehler bei Rodelbahn '%s': " % sl.page_title + unicode_e(e)
         model.meta.Session.commit()
         
         # Redirect to result page
index 5db13d96ea0f3123d2479d76c806eb3e1f843bee..646a03634e263bfbd060849a861625bd41b2f329 100644 (file)
@@ -7,6 +7,7 @@ available to Controllers. This module is available to templates as 'h'.
 #from webhelpers.html.tags import checkbox, password
 
 from routes import url_for
+import wradmin.model.validators
 
 def wiki(page_title=None):
     "Creates a link to the specified page in the www.winterrodeln.org wiki"
@@ -27,14 +28,9 @@ def google_maps(latitude, longitude):
 
 def bool(value):
     "Takes a bool value and creates a German representation"
-    if value is None: return None
-    if value: return u'Ja'
-    return u'Nein'
+    return wradmin.model.validators.GermanBool().from_python(value)
 
 
 def tristate(yes, no):
     "Takes a German representation of a tristate value"
-    if yes is None or no is None: return None
-    if yes == no: return u'Teilweise'
-    if yes: return u'Ja'
-    if no: return u'Nein'
+    return wradmin.model.validators.GermanTristate().from_python((yes, no))
index 98da47a071e6d556cbd83e3bb6782c44c1efeffb..5351d4b6bff59f7b825e08ae88fb234f65b2ecb6 100644 (file)
@@ -2,8 +2,9 @@
 
 from authkit.users import UsersReadOnly, md5
 import datetime
-import re
 import wradmin.model as model
+import wradmin.model.validators
+import formencode, formencode.national
 
 import logging
 log = logging.getLogger(__name__)
@@ -13,31 +14,22 @@ log = logging.getLogger(__name__)
 # -------------------
 
 def to_bool(value):
-    if not value: return None
-    if value == u'Ja': return True
-    if value == u'Nein': return False
-    raise Exception(u"'%s' is not a valid boolean value, use one of 'Ja' or 'Nein'" % value)
+    return model.validators.GermanBool().to_python(value)
 
 
 def to_unsigned(value):
-    if value is None or value == u'': return None
-    v = int(value)
-    if v < 0: raise Exception('The value %v has to be positive.')
-    return v
+    "Requires a positive number"
+    return formencode.validators.Int(min=0).to_python(value)
 
 
 def to_date(value):
     "Parses a date in the form 'yyy-mm-dd'"
-    if value is None: return None
-    return datetime.datetime.strptime(value, '%Y-%m-%d')
+    return model.validators.DateConverter().to_python(value)
 
 
 def to_geo(value):
     "Formats to coordinates '47.076207 N 11.453553 E' to the (latitude, longitude) tuplet."
-    if not value: return (None, None)
-    r = re.match(u'(\d+\.\d+) N (\d+\.\d+) E', value)
-    if r is None: raise Exception(u"Coordinates '%s' have not a format like '47.076207 N 11.453553 E'" % value)
-    return (float(r.groups()[0]), float(r.groups()[1]))
+    return model.validators.Geo().to_python(value)
 
 
 def to_title(value):
@@ -52,29 +44,26 @@ def to_tristate(value):
     u'Ja'        -> (True, False)
     u'Teilweise' -> (True,  True)
     u'Nein'      -> (False, True)"""
-    if value is None: return (None, None)
-    elif value == u'Ja': return (True, False)
-    elif value == u'Nein': return (False, True)
-    elif value == u'Teilweise': return (True, True)
-    raise Exception(u"The value has to be one of 'Ja', 'Nein' or 'Teilweise', not '%s'" % value)
+    return model.validators.GermanTristate().to_python(value)
 
 
 def to_email(value):
-    return value #!!!! TODO
+    return formencode.validators.Email().to_python(value)
 
 
 def to_url(value):
-    return value #!!!! TODO
+    return formencode.validators.URL().to_python(value)
 
 
 def to_phone(value):
-    return value #!!!! TODO
+    # return formencode.national.InternationalPhoneNumber(default_cc=43, messages={'phoneFormat': u"Telefonnummer muss das Format 0123/456789 oder +43/123/456789 haben"}).to_python(value)
+    return value # I should write my own PhoneNumber check.
 
 
 def conv(fnct, value, fieldname):
     "Like one of the to_xxx functions (e.g. to_bool), but adds the field name to the error message"
     try: return fnct(value)
-    except Exception, e: raise Exception(u"Conversion error in field '%s': %s" % (fieldname, unicode_e(e)))
+    except formencode.Invalid, e: raise formencode.Invalid(u"Conversion error in field '%s': %s" % (fieldname, unicode_e(e)), e.value, e.state)
 
 
 def unicode_e(exception):
diff --git a/wradmin/wradmin/model/validators.py b/wradmin/wradmin/model/validators.py
new file mode 100644 (file)
index 0000000..94955b7
--- /dev/null
@@ -0,0 +1,112 @@
+# -*- coding: iso-8859-15 -*-
+
+import formencode
+import datetime
+import re
+
+
+class GermanBool(formencode.FancyValidator):
+    "Converts German bool values to the python bool type. 'Ja' and 'Nein' are supported."
+    
+    def __init__(self, yes = [u'Ja'], no = [u'Nein'], **keywords):
+        "The yes and no arguments specify the valid possibilities. The first possibility is the default one."
+        formencode.FancyValidator.__init__(self, **keywords)
+        self.yes = yes
+        self.no = no
+    
+    def _to_python(self, value, state):
+        self.assert_string(value, state)
+        if value in self.yes: return True
+        if value in self.no: return False
+        all = self.yes[:]
+        all.extend(self.no)
+        raise formencode.Invalid(u"'%s' is not a valid boolean value, use one of %s" % (value, all), value, state)
+    
+    def from_python(self, value):
+        if value is None: return u''
+        if value: return self.yes[0]
+        return self.no[0]
+
+
+class GenericDateTimeConverter(formencode.FancyValidator):
+    """Converts generic date/time information to datetime classes with a user defined format.
+    '2009-03-22 20:36:15' would be specified as '%Y-%m-%d %H:%M:%S'."""
+    
+    def __init__(self, date_time_format = '%Y-%m-%d %H:%M:%S', **keywords):
+        formencode.FancyValidator.__init__(self, **keywords)
+        self.date_time_format = date_time_format
+    
+    def _to_python(self, value, state):
+        self.assert_string(value, state)
+        try: return datetime.datetime.strptime(value, self.date_time_format)
+        except ValueError, e: raise formencode.Invalid(str(e), value, state)
+    
+    def _from_python(self, value, state):
+        if value is None: return u''
+        return value.strftime(self.date_time_format)
+
+
+class DateTimeNoSecConverter(GenericDateTimeConverter):
+    def __init__(self, **keywords):
+        GenericDateTimeConverter.__init__(self, '%Y-%m-%d %H:%M', **keywords)
+
+
+class DateConverter(GenericDateTimeConverter):
+    "Converts date information to date classes with the format '%Y-%m-%d'."
+    
+    def __init__(self, **keywords):
+        GenericDateTimeConverter.__init__(self, '%Y-%m-%d', **keywords)
+    
+    def _to_python(self, value, state):
+        GenericDateTimeConverter._to_python(self, value, state).date()
+
+
+class GermanTristate(formencode.FancyValidator):
+    """Does the following conversion:
+    None         -> (None, None)
+    u'Ja'        -> (True, False)
+    u'Teilweise' -> (True,  True)
+    u'Nein'      -> (False, True)"""
+    
+    def __init__(self, yes_python = (True, False), no_python = (False, True), partly_python = (True, True), yes_text = [u'Ja'], no_text = [u'Nein'], partly_text = [u'Teilweise'], **keywords):
+        formencode.FancyValidator.__init__(self, if_empty = (None, None), **keywords)
+        self.yes_python = yes_python
+        self.no_python = no_python
+        self.partly_python = partly_python
+        self.yes_text = yes_text
+        self.no_text = no_text
+        self.partly_text = partly_text
+    
+    def _to_python(self, value, state):
+        self.assert_string(value, state)
+        if value in self.yes_text: return self.yes_python
+        if value in self.no_text: return self.no_python
+        if value in self.partly_text: return self.partly_python
+        all = self.yes_text[:]
+        all.extend(self.no_text)
+        all.extend(self.partly_text)
+        raise formencode.Invalid(u"'%s' is not a valid value, use one of %s" % (value, all), value, state)
+    
+    def _from_python(self, value, state):
+        if value == (None, None): return ''
+        if value == self.yes_python: return self.yes_text[0]
+        if value == self.no_python: return self.no_text[0]
+        if value == self.partly_python: return self.partly_text[0]
+        raise formencode.Invalid(u"Invalid representation of a tristate value: '%s'" % (value,), value, state)
+
+
+class Geo(formencode.FancyValidator):
+    "Formats to coordinates '47.076207 N 11.453553 E' to the (latitude, longitude) tuplet."
+    
+    def __init__(self, **keywords):
+        formencode.FancyValidator.__init__(self, if_empty = (None, None), **keywords)
+    
+    def _to_python(self, value, state):
+        r = re.match(u'(\d+\.\d+) N (\d+\.\d+) E', value)
+        if r is None: raise formencode.Invalid(u"Coordinates '%s' have not a format like '47.076207 N 11.453553 E'" % value, value, state)
+        return (float(r.groups()[0]), float(r.groups()[1]))
+    
+    def _from_python(self, value, state):
+        if value == (None, None): return ''
+        latitude, longitude = value
+        return u'%.6f N %.6f E' % (latitude, longitude)
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..75946faf5a8001ebd92d37e119d45732de8194ce 100644 (file)
@@ -0,0 +1,48 @@
+import wradmin.model.validators
+import formencode
+
+def test_bool_validator():
+    v =  wradmin.model.validators.GermanBool()
+    assert v.to_python(u'Ja') == True
+    assert v.to_python(u'Nein') == False
+    assert v.to_python(None) == None
+    assert v.to_python(u'') == None
+    try:
+        v.to_python(u'Wrong')
+        assert True, u"The value 'Wrong' must not be accepted by the validator."
+    except formencode.Invalid: pass
+    
+    assert v.from_python(True) == u'Ja'
+    assert v.from_python(False) == u'Nein'
+    assert v.from_python(None) == u''
+
+
+def test_GermanTristate_validator():
+    v = wradmin.model.validators.GermanTristate()
+    assert v.to_python(u'Ja') == (True, False)
+    assert v.to_python(u'Nein') == (False, True)
+    assert v.to_python(u'Teilweise') == (True,  True)
+    assert v.to_python(u'') == (None, None)
+    assert v.to_python(None) == (None, None)
+    try:
+        v.to_python(u'Wrong')
+        assert True, u"The value 'Wrong' must not be accepted by the validator."
+    except formencode.Invalid: pass
+
+    assert v.from_python((True, False)) == u'Ja'
+    assert v.from_python((False, True)) == u'Nein'
+    assert v.from_python((True, True)) == u'Teilweise'
+    assert v.from_python((None, None)) == u''
+
+
+def test_geo():
+    coord = u'47.076207 N 11.453553 E'
+    v = wradmin.model.validators.Geo()
+    (lat, lon) = v.to_python(coord)
+    assert lat == 47.076207
+    assert lon == 11.453553
+    assert v.to_python(u'') == (None, None)
+
+    assert v.from_python((lat, lon)) == coord
+    assert v.from_python((None, None)) == u''
+