]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/blob - wradmin/wradmin/model/validators.py
25c81d9bb2fba9cb4e2a215b8586292ec9a47d43
[philipp/winterrodeln/wradmin.git] / wradmin / wradmin / model / validators.py
1 # -*- coding: iso-8859-15 -*-
2
3 import formencode
4 import datetime
5 import re
6
7
8 class GermanBool(formencode.FancyValidator):
9     "Converts German bool values to the python bool type. 'Ja' and 'Nein' are supported."
10     
11     def __init__(self, yes = [u'Ja'], no = [u'Nein'], **keywords):
12         "The yes and no arguments specify the valid possibilities. The first possibility is the default one."
13         formencode.FancyValidator.__init__(self, **keywords)
14         self.yes = yes
15         self.no = no
16     
17     def _to_python(self, value, state):
18         self.assert_string(value, state)
19         if value in self.yes: return True
20         if value in self.no: return False
21         all = self.yes[:]
22         all.extend(self.no)
23         raise formencode.Invalid(u"'%s' is not a valid boolean value, use one of %s" % (value, all), value, state)
24     
25     def from_python(self, value):
26         if value is None: return u''
27         if value: return self.yes[0]
28         return self.no[0]
29
30
31 class GenericDateTimeConverter(formencode.FancyValidator):
32     """Converts generic date/time information to datetime classes with a user defined format.
33     '2009-03-22 20:36:15' would be specified as '%Y-%m-%d %H:%M:%S'."""
34     
35     def __init__(self, date_time_format = '%Y-%m-%d %H:%M:%S', **keywords):
36         formencode.FancyValidator.__init__(self, **keywords)
37         self.date_time_format = date_time_format
38     
39     def _to_python(self, value, state):
40         self.assert_string(value, state)
41         try: return datetime.datetime.strptime(value, self.date_time_format)
42         except ValueError, e: raise formencode.Invalid(str(e), value, state)
43     
44     def _from_python(self, value, state):
45         if value is None: return u''
46         return value.strftime(self.date_time_format)
47
48
49 class DateTimeNoSecConverter(GenericDateTimeConverter):
50     def __init__(self, **keywords):
51         GenericDateTimeConverter.__init__(self, '%Y-%m-%d %H:%M', **keywords)
52
53
54 class DateConverter(GenericDateTimeConverter):
55     "Converts date information to date classes with the format '%Y-%m-%d'."
56     
57     def __init__(self, **keywords):
58         GenericDateTimeConverter.__init__(self, '%Y-%m-%d', **keywords)
59     
60     def _to_python(self, value, state):
61         GenericDateTimeConverter._to_python(self, value, state).date()
62
63
64 class GermanTristate(formencode.FancyValidator):
65     """Does the following conversion:
66     None         -> (None, None)
67     u'Ja'        -> (True, False)
68     u'Teilweise' -> (True,  True)
69     u'Nein'      -> (False, True)"""
70     
71     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):
72         formencode.FancyValidator.__init__(self, if_empty = (None, None), **keywords)
73         self.yes_python = yes_python
74         self.no_python = no_python
75         self.partly_python = partly_python
76         self.yes_text = yes_text
77         self.no_text = no_text
78         self.partly_text = partly_text
79     
80     def _to_python(self, value, state):
81         self.assert_string(value, state)
82         if value in self.yes_text: return self.yes_python
83         if value in self.no_text: return self.no_python
84         if value in self.partly_text: return self.partly_python
85         all = self.yes_text[:]
86         all.extend(self.no_text)
87         all.extend(self.partly_text)
88         raise formencode.Invalid(u"'%s' is not a valid value, use one of %s" % (value, all), value, state)
89     
90     def _from_python(self, value, state):
91         if value == (None, None): return ''
92         if value == self.yes_python: return self.yes_text[0]
93         if value == self.no_python: return self.no_text[0]
94         if value == self.partly_python: return self.partly_text[0]
95         raise formencode.Invalid(u"Invalid representation of a tristate value: '%s'" % (value,), value, state)
96
97
98 class Geo(formencode.FancyValidator):
99     "Formats to coordinates '47.076207 N 11.453553 E' to the (latitude, longitude) tuplet."
100     
101     def __init__(self, **keywords):
102         formencode.FancyValidator.__init__(self, if_empty = (None, None), **keywords)
103     
104     def _to_python(self, value, state):
105         r = re.match(u'(\d+\.\d+) N (\d+\.\d+) E', value)
106         if r is None: raise formencode.Invalid(u"Coordinates '%s' have not a format like '47.076207 N 11.453553 E'" % value, value, state)
107         return (float(r.groups()[0]), float(r.groups()[1]))
108     
109     def _from_python(self, value, state):
110         if value == (None, None): return ''
111         latitude, longitude = value
112         return u'%.6f N %.6f E' % (latitude, longitude)
113
114
115 class MultiGeo(formencode.FancyValidator):
116     "Formats multiple coordinates, even in multiple lines to [(latitude, longitude, height), ...] or [(latitude, longitude, None), ...] tuplets."
117     
118     # Valid for input_format
119     FORMAT_GUESS = 0         # guesses the input format; default for input_format
120     FORMAT_NONE = -1          # indicates missing formats
121     
122     # Valid for input_format and output_format
123     FORMAT_GEOCACHING = 1    # e.g. "N 47° 13.692 E 011° 25.535"
124     FORMAT_WINTERRODELN = 2  # e.g. "47.222134 N 11.467211 E"
125     FORMAT_GMAPPLUGIN = 3    # e.g. "47.232922, 11.452239"
126     FORMAT_GPX = 4           # e.g. "<trkpt lat="47.181289" lon="11.408827"><ele>1090.57</ele></trkpt>"
127     
128     input_format = FORMAT_GUESS
129     output_format = FORMAT_WINTERRODELN
130     last_input_format = FORMAT_NONE
131
132     def __init__(self, input_format = FORMAT_GUESS, output_format = FORMAT_WINTERRODELN, **keywords):
133         self.input_format = input_format
134         self.output_format = output_format
135         formencode.FancyValidator.__init__(self, if_empty = (None, None, None), **keywords)
136     
137     def _to_python(self, value, state):
138         input_format = self.input_format
139         if not input_format in [self.FORMAT_GUESS, self.FORMAT_GEOCACHING, self.FORMAT_WINTERRODELN, self.FORMAT_GMAPPLUGIN, self.FORMAT_GPX]:
140             raise formencode.Invalid(u"input_format %d is not recognized" % input_format, value, state) # Shouldn't it be an other type of runtime error?
141         lines = [line.strip() for line in value.split("\n") if len(line.strip()) > 0]
142         
143         result = []
144         for line in lines:
145             if input_format == self.FORMAT_GUESS or input_format == self.FORMAT_GEOCACHING:
146                 pass
147                 
148             if input_format == self.FORMAT_GUESS or input_format == self.FORMAT_WINTERRODELN:
149                 r = re.match(u'(\d+\.\d+) N (\d+\.\d+) E', line)
150                 if not r is None:
151                     result.append((float(r.groups()[0]), float(r.groups()[1]), None))
152                     last_input_format = self.FORMAT_WINTERRODELN
153                     continue
154                 
155             if input_format == self.FORMAT_GUESS or input_format == FORMAT_GMAPPLUGIN:
156                 pass
157                 
158             if input_format == self.FORMAT_GUESS or input_format == self.FORMAT_GPX:
159                 pass
160             
161             raise formencode.Invalid(u"Coordinates '%s' have no valid format" % value, value, state)
162             
163         return result
164     
165     def _from_python(self, value, state):
166         output_format = self.output_format
167         result = []
168         for latitude, longitude, height in value:
169             if output_format == self.FORMAT_GEOCACHING:
170                 degree = latitude
171                 result.append(u'N %02d° %02.3f E %03d° %02.3f' % (latitude, latitude % 1 * 60, longitude, longitude % 1 * 60))
172                 
173             elif output_format == self.FORMAT_WINTERRODELN:
174                 result.append(u'%.6f N %.6f E' % (latitude, longitude))
175
176             elif output_format == FORMAT_GMAPPLUGIN:
177                 pass
178                 
179             elif output_format == self.FORMAT_GPX:
180                 pass
181             
182             else:
183                 raise formencode.Invalid(u"output_format %d is not recognized" % output_format, value, state) # Shouldn't it be an other type of runtime error?
184             
185         return "\n".join(result)
186
187
188 class AustrianPhoneNumber(formencode.FancyValidator):
189     """
190     Validates and converts phone numbers to +##/###/####### or +##/###/#######-### (having an extension)
191     @param  default_cc      country code for prepending if none is provided, defaults to 43 (Austria)
192     ::
193         >>> v = AustrianPhoneNumber()
194         >>> v.to_python(u'0512/12345678')
195         u'+43/512/12345678'
196         >>> v.to_python(u'+43/512/12345678')
197         u'+43/512/12345678'
198         >>> v.to_python(u'0512/1234567-89') # 89 is the extension
199         u'+43/512/1234567-89'
200         >>> v.to_python(u'+43/512/1234567-89')
201         u'+43/512/1234567-89'
202         >>> v.to_python(u'0512 / 12345678') # Exception
203         >>> v.to_python(u'0512-12345678') # Exception
204     """
205     # Inspired by formencode.national.InternationalPhoneNumber
206
207     default_cc = 43 # Default country code
208     messages = {'phoneFormat': "'%%(value)s' is an invalid format. Please enter a number in the form +43/###/####### or 0###/########."}
209
210     def _to_python(self, value, state):
211         self.assert_string(value, state)
212         m = re.match(u'^(?:\+(\d+)/)?([\d/]+)(?:-(\d+))?$', value)
213         # This will separate 
214         #     u'+43/512/1234567-89'  => (u'43', u'512/1234567', u'89')
215         #     u'+43/512/1234/567-89' => (u'43', u'512/1234/567', u'89')
216         #     u'+43/512/1234/567'    => (u'43', u'512/1234/567', None)
217         #     u'0512/1234567'        => (None, u'0512/1234567', None)
218         if m is None: raise formencode.Invalid(self.message('phoneFormat', state) % {'value': value}, value, state)
219         (country, phone, extension) = m.groups()
220         
221         # Phone
222         if phone.find(u'//') > -1 or phone.count('/') == 0: raise formencode.Invalid(self.message('phoneFormat', state) % {'value': value}, value, state)
223         
224         # Country
225         if country is None:
226             if phone[0] != '0': raise formencode.Invalid(self.message('phoneFormat', state) % {'value': value}, value, state)
227             phone = phone[1:]
228             country = unicode(self.default_cc)
229         
230         if extension is None: return '+%s/%s' % (country, phone)
231         return '+%s/%s-%s' % (country, phone, extension)
232
233
234 class PhoneInfo(formencode.FancyValidator):
235     "Validates a info of the form '0644/1234567 (Schnee Alm)'"
236     messages = {'infoFormat': "'%%(value)s' is no valid format, please use a form like '0644/1234567 (Schnee Alm)'"}
237     
238     def _to_python(self, value, state):
239         self.assert_string(value, state)
240         m = re.match('^([-\d/\+]{5,}) \((.+)\)', value)
241         if m is None: raise formencode.Invalid(self.message('infoFormat', state) % {'value': value}, value, state)
242         (phone, info) = m.groups()
243         
244         # check phone
245         phone = AustrianPhoneNumber().to_python(phone)
246         
247         return "%s (%s)" % (phone, info)