]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/commitdiff
On the way to version 1.3.
authorphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Sun, 20 Jun 2010 13:05:46 +0000 (13:05 +0000)
committerphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Sun, 20 Jun 2010 13:05:46 +0000 (13:05 +0000)
git-svn-id: http://www.winterrodeln.org/svn/servermediawiki/trunk/wradmin@567 7aebc617-e5e2-0310-91dc-80fb5f6d2477

wradmin/setup.py
wradmin/wradmin/controllers/rodelbahn.py
wradmin/wradmin/lib/mediawiki.py
wradmin/wradmin/model/__init__.py
wradmin/wradmin/model/validators.py
wradmin/wradmin/templates/rodelbahn_list.html
wradmin/wradmin/templates/rodelbahn_view.html
wradmin/wradmin/templates/wrgpxtool.html
wradmin/wradmin/tests/test_lib.py
wradmin/wradmin/tests/test_models.py

index 58f8be25f8325008cd1c24f1dc0d8f861428176f..06bdc36d05ce5a01fada50467c5e1841dbdb8d3b 100644 (file)
@@ -19,7 +19,7 @@ setup(
         "AuthKit>=0.4.3,<=0.4.99",
         "SQLAlchemy>=0.5",
         "lxml>=2.2",
-        "matplotlib>=0.9",
+        "matplotlib>=0.9",
         "Babel>=0.9"
     ],
     setup_requires=["PasteScript>=1.6.3"],
index 7c3b8063f30852d9c48362f3b17f9508215f0dba..237e6e4f592861ec5382bb084fc8af954997b873 100644 (file)
@@ -20,6 +20,7 @@ class RodelbahnController(BaseController):
     def index(self):
         return render('index.html')
 
+
     def list(self):
         "Lists all sledding routes"
         q = model.meta.Session.query(model.WrSleddingCache)
@@ -41,6 +42,9 @@ class RodelbahnController(BaseController):
     
     def _wikipage_to_wrsleddingcache(self, sledding_wiki):
         "Converts a sledding route wiki page to a sledding route wrsleddingcache database record."
+        # TODO: Use mediawiki.wikipage_to_wrsleddingcache
+        
+        
         sl = model.WrSleddingCache()
         sl.page_id = sledding_wiki.page_id
         sl.page_title = to_title(sledding_wiki.page_title)
index 378dd808365903224fd8131d74aad29d46fcb26b..8ab55f6a2e67abdb9d5b04ccb6ff084f78f304e6 100644 (file)
@@ -1,14 +1,18 @@
+#!/usr/bin/python2.5
+# -*- coding: iso-8859-15 -*-
+# $Id$
 "MediaWiki communication functions"
+import datetime
+import re
 
 from authkit.users import UsersReadOnly, md5
-import datetime
-import wradmin.model as model
-import wradmin.model.validators
 import formencode, formencode.national
-
 import logging
 log = logging.getLogger(__name__)
 
+import wradmin.model as model
+import wradmin.model.validators
+
 
 # Converter functions
 # -------------------
@@ -22,6 +26,19 @@ def to_unsigned(value):
     return formencode.validators.Int(min=0).to_python(value)
 
 
+def from_unsigned(value):
+    """None -> ''
+    integer -> unicode"""
+    if value is None: return ''
+    return unicode(value)
+
+
+def to_string(value):
+    "Converts an empty string to None."
+    if len(value) == 0: return None
+    return value
+
+
 def to_date(value):
     "Parses a date in the form 'yyy-mm-dd'"
     return model.validators.DateConverter().to_python(value)
@@ -52,17 +69,184 @@ def to_email(value):
 
 
 def to_url(value):
-    return formencode.validators.URL().to_python(value)
+    # return formencode.validators.URL().to_python(value) # does not accept URLs with accents
+    if value == '': return None
+    if not value.startswith('http'): raise formencode.Invalid('URL does not start with http.', value, None)
+    return value
 
 
+# deprecated
 def to_phone(value):
     return model.validators.AustrianPhoneNumber(messages={'phoneFormat': u"Telefonnummer %%(value)s muss das Format 0123/456789 oder +43/123/456789 haben"}).to_python(value)
 
 
+# deprecated
 def to_phone_info(value):
     return model.validators.PhoneInfo(messages={'phoneInfo': u"Bitte verwenden Sie ein Format wie '0512/123456 (Schnee Alm)'."}).to_python(value)
 
 
+def to_walkup_separate(value):
+    """'Ja', 'Nein', 'Teilweise' -> 1, 0, 0.5. A comment is allowed."""
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None: return None, None
+    if len(v) > 1: raise formencode.Invalid('Only one field is allowed.', value, None)
+    return formencode.validators.DictConverter({u'Ja': 1.0, u'Teilweise': 0.5, u'Nein': 0.0}).to_python(v[0][0]), v[0][1]
+
+
+def to_lift(value):
+    """Example 'Gondel (nur tagsüber); Taxi'"""
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None: return None, None
+    has_lift = None
+    for vv, comment in v:
+        if vv == u'Nein':
+            if len(vv) != 1: raise formencode.Invalid('"Nein" kann mit keiner anderen Aufstiegshilfe kombiniert werden.', value, None)
+            lift = False
+        elif not vv in [u'Sessellift', u'Gondel', u'Linienbus', u'Taxi', u'Sonstige']:
+            raise formencode.Invalid(u'"%s" ist keine gültige Aufstiegshilfe.' % vv, vv, None)
+        else: has_lift = True
+    return has_lift, value
+
+
+def to_night_light(value):
+    """Examle: 'Teilweise (im unteren Teil)'"""
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None: return None, None
+    if len(v) > 1: raise formencode.Invalid('Only one field is allowed.', value, None)
+    return formencode.validators.DictConverter({u'Ja': 1.0, u'Teilweise': 0.5, u'Nein': 0.0}).to_python(v[0][0]), v[0][1]
+
+
+def to_night_light_days(value):
+    """Example: '3 (Montag, Mittwoch, Freitag)'"""
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None: return None, None
+    if len(v) > 1: raise formencode.Invalid('Only one field is allowed.', value, None)
+    return to_unsigned(v[0][0]), v[0][1]
+
+
+def to_sled_rental(value):
+    """Example: 'Talstation Serlesbahnan; [[Pinnisalm]]'"""
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None: return None, None
+    sled_rental = True
+    if len(v) == 1: 
+        if v[0][0] == 'Nein': return False, None
+    return True, value
+
+
+def to_cachet(value):
+    if value == '': return None
+    elif value == 'Nein': return value
+    elif value.startswith(u'Tiroler Naturrodelbahn-Gütesiegel '):
+        p = value.split(" ")
+        to_unsigned(p[2]) # check if year can be parsed
+        if not p[3] in ['leicht', 'mittel', 'schwer']: raise formencode.Invalid("Unbekannter Schwierigkeitsgrad", value, None)
+        return value
+    else: raise formencode.Invalid("Unbekanntes Gütesiegel", value, None)
+
+
+def to_information_web(value):
+    if value == 'Nein': return value
+    to_url(value) # is the URL valid?
+    return value
+
+
+def to_information_phone(value):
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None: return None
+    c = formencode.national.InternationalPhoneNumber(default_cc=lambda: 43)
+    for t  in v:
+        if t[0] == 'Nein':
+            if len(v) != 1: raise formencode.Invalid("Bei 'Nein' ist nur ein Eintrag erlaubt", value, None)
+        else:
+            if c.to_python(t[0]) != t[0]: raise formencode.Invalid(u"Telefonnummer hat nicht das gewünschte Format.", value, None)
+            if (t[1] is None): raise formencode.Invalid(u"Bei Telefonnummern muss ein Kommentar angegeben werden.", value, None)
+    return value
+
+
+def to_overnight(value):
+    """'Nein' -> False, None
+    <unparsed text> -> True, <unparsed text>"""
+    if value == '': return None, None
+    if value == 'Nein': return False, None
+    return True, value
+
+
+def from_overnight(is_possible, comment):
+    """is_possible can be None, True or False
+    comment has to be a unicode string."""
+    if is_possible is None:
+        assert comment is None
+        return ''
+    if not is_possible:
+        assert comment is None
+        return u'Nein'
+    return comment
+
+
+def to_sled_rental_inn(value):
+    """'Nein' -> False, None
+    <unparsed text> -> True, <unparsed text>"""
+    return to_overnight(value) # same implementation as to_overnight
+
+
+def from_sled_rental_inn(is_possible, comment):
+    return from_overnight(is_possible, comment) # same implementation
+
+
+def to_forum_id(value):
+    if value == u'Nein': return 0
+    return to_unsigned(value)
+
+
+def to_mobile_provider(value):
+    """A1; T-Mobile A (gut)"""
+    model.validators.ValueCommentList().to_python(value) # no exception should be raised.
+    return value
+
+
+def to_email_list(value):
+    """Converts a list of email addresses with optional comments to the primary (first) adress,
+    comment for the primary address and the complete list.
+    >>> email_primary, email_primary_comment, email_list = to_email_list('first@example.com (Nur Winter); second@example.com')
+    >>> print email_primary
+    'first@example.com'
+    >>> print email_primary_comment
+    'Nur Winter'
+    >>> print email_list
+    'first@example.com (Nur Winter); second@example.com'
+    """
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None or len(v) == 0: return None, None, None
+    for e, c in v: to_email(e) # check for valid addresses
+    return v[0][0], v[0][1], v
+
+
+def to_phone_list(value):
+    """Converts a list of internationa telephone number with optional comments to the primary (first) number,
+    comment for the primary number and the complete list.
+    >>> phone_primary, phone_primary_comment, phone_list = to_phone_list('+43-699-1234567 (nicht nach 20:00 Uhr); +43-512-123456')
+    >>> print phone_primary
+    '+43-699-1234567'
+    >>> print phone_primary_comment
+    'nicht nach 20:00 Uhr'
+    >>> print phone_list
+    '+43-699-1234567 (nicht nach 20:00 Uhr); +43-512-123456'
+    """
+    v = model.validators.ValueCommentList().to_python(value)
+    if v is None or len(v) == 0: return None, None, None
+    ip = formencode.national.InternationalPhoneNumber(default_cc=lambda: 43)
+    for p, c in v: ip.to_python(p) # check for valid phone numbers
+    return v[0][0], v[0][1], v
+
+
+def to_wiki_list(value):
+    """Validates a list of wiki pages like "[[Birgitzer Alm]]; [[Kemater Alm]]" """
+    v = value.split(";")
+    for w in v:
+        if not w.startswith('[[') or not w.endswith(']]'): raise formencode.Invalid('No valid wiki page name', value, None)
+
+
 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)
@@ -77,6 +261,417 @@ def unicode_e(exception):
     return unicode(exception)
 
 
+def wikipage_to_wrsleddingcache1_2(page_id, page_title, page_text):
+    """Converts a wiki page about a sledding route to a wradmin.model.WrSleddingCache1_2 class
+    that can be inserted to the wradmin.model.wrsleddingcache1_2_table.
+    It needs the wiki page id, the wiki page title and the page text ("old_text") as they come from the database."""
+    sl = model.WrSleddingCache1_2()
+    sl.page_id = page_id
+    sl.page_title = to_title(page_title)
+    
+    # Match Rodelbahnbox
+    wikitext = page_text
+    regexp = re.compile(u"\{\{(Rodelbahnbox[^\}]*)\}\}", re.DOTALL)
+    match = regexp.search(wikitext)
+    if not match:
+        raise Exception(u"No 'Rodelbahnbox' found")
+    box = match.group(1)
+    
+    # Process Rodelbahnbox
+    for property in box.split('|'):
+        property = property.strip()
+        if property == u'Rodelbahnbox': continue
+        key_value = property.split('=')
+        if len(key_value) != 2:
+            raise Exception(u"Property '%s' has unexpected format" % key_value)
+        key = key_value[0].strip()
+        value = key_value[1].strip()
+        if key == u'Rodelbahnnummer': pass
+        elif key == u'Länge': sl.length = conv(to_unsigned, value, u'Länge')
+        elif key == u'Gehzeit': sl.walktime = conv(to_unsigned, value, u'Gehzeit')
+        elif key == u'Höhe oben': sl.height_top = conv(to_unsigned, value, u'Höhe oben')
+        elif key == u'Höhe unten': sl.height_bottom = conv(to_unsigned, value, u'Höhe unten')
+        elif key == u'Aufstieg getrennt': sl.walkup_separate = conv(to_bool, value, u'Aufstieg getrennt')
+        elif key == u'Lift': sl.lift = conv(to_bool, value, u'Lift')
+        elif key == u'Beleuchtung': sl.night_light = conv(to_bool, value, u'Beleuchtung')
+        elif key == u'Rodelverleih': sl.sledge_rental = conv(to_bool, value, u'Rodelverleih')
+        elif key == u'Öffentliche Anreise': sl.public_transport = conv(to_bool, value, u'Öffentliche Anreise')
+        elif key == u'Bild': sl.image = conv(to_string, value, key)
+        elif key == u'Position': (sl.position_latitude, sl.position_longitude) = conv(to_geo, value, u'Position') # '47.583333 N 15.75 E'
+        elif key == u'Auskunft': sl.information = conv(to_phone_info, value, u'Auskunft')
+        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'
+        elif key == u'Lawinengefahr':
+            # sl.avalanches is not part of the 1.2 sleddingcache table. We store it in the WrSleddingCache1_2 anyway.
+            sl.avalanches = conv(model.validators.GermanAvalanches().to_python, value, key)
+        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}})
+    match = re.search(u"\{\{Forumlink\|(\d+)\}\}", wikitext)
+    if match: sl.forum_id = match.group(1)
+    
+    return sl
+
+
+def wikipage_to_wrsleddingcache(wiki_page):
+    """Converts a sled-route wiki page (wradmin.model.page_table) 
+    to a sledding route wrsleddingcache database record (wradmin.model.wrsleddingcache_table).
+    Raises a RuntimeError if the format is not OK
+    sledding_wiki is a column of tabe "page".
+    Returns the WrSleddingCache class"""
+    sl = model.WrSleddingCache()
+    sl.page_id = wiki_page.page_id
+    sl.page_title = to_title(wiki_page.page_title)
+    errors = [] # List of errors with localized messages
+    
+    # Match Rodelbahnbox
+    wikitext = wiki_page.old_text
+    regexp = re.compile(u"\{\{(Rodelbahnbox[^\}]*)\}\}", re.DOTALL)
+    match = regexp.search(wikitext)
+    if not match:
+        raise RuntimeError(_(u"No 'Rodelbahnbox' found"))
+    box = match.group(1)
+    
+    # Process Rodelbahnbox
+    for property in box.split('|'):
+        property = property.strip()
+        if property == u'Rodelbahnbox': continue
+        key_value = property.split('=')
+        if len(key_value) != 2:
+            raise RuntimeError(_(u"Property '%s' has unexpected format") % key_value)
+        key = key_value[0].strip()
+        value = key_value[1].strip()
+        if key in [u'Rodelbahnnummer', u'Lift']:
+            errors.append(_("Property '%s' is not supported anymore, see %s.") % (key, 'http://www.winterrodeln.org/wiki/Vorlage:Rodelbahnbox'))
+        elif key == u'Position': (sl.position_latitude, sl.position_longitude) = conv(to_geo, value, key) # '47.583333 N 15.75 E'
+        elif key == u'Position oben': (sl.top_latitude, sl.top_longitude) = conv(to_geo, value, key) # '47.583333 N 15.75 E'
+        elif key == u'Höhe oben': sl.top_elevation = conv(to_unsigned, value, key) # '2000'
+        elif key == u'Position unten': (sl.bottom_latitude, sl.bottom_longitude) = conv(to_geo, value, key) # '47.583333 N 15.75 E'
+        elif key == u'Höhe unten': sl.bottom_elevation = conv(to_unsigned, value, key) # '1200'
+        elif key == u'Länge': sl.length = conv(to_unsigned, value, key) # 3500
+        elif key == u'Schwierigkeit': sl.difficulty = conv(model.validators.GermanDifficulty().to_python, value, key) # 'mittel'
+        elif key == u'Lawinen': sl.avalanches = conv(model.validators.GermanAvalanches().to_python, value, key) # 'kaum'
+        elif key == u'Betreiber': sl.operator = value # 'Max Mustermann'
+        elif key == u'Öffentliche Anreise': sl.public_transport = conv(model.validators.GermanPublicTransport().to_python, value, key) # 'Mittelmäßig'
+        elif key == u'Gehzeit': sl.walkup_time = conv(to_unsigned, value, key) # 90
+        elif key == u'Aufstieg getrennt': sl.walkup_separate, sl.walkup_separate_comment = conv(to_walkup_separate, value, key) # 'Ja'
+        elif key == u'Aufstiegshilfe': sl.lift, sl.lift_comment = conv(to_lift, value, key) # 'Gondel (unterer Teil)'
+        elif key == u'Beleuchtungsanlage': sl.night_light, sl.night_light_comment = conv(to_night_light, value, key)
+        elif key == u'Beleuchtungstage': sl.night_light_days, sl.night_light_days_comment = conv(to_night_light_days, value, key) # '3 (Montag, Mittwoch, Freitag)'
+        elif key == u'Rodelverleih': sl.sled_rental, sl.sled_rental_comment = conv(to_sled_rental, value, key) # 'Talstation Serlesbahnan'
+        elif key == u'Gütesiegel': sl.cachet = conv(to_cachet, value, key) # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
+        elif key == u'Webauskunft': sl.information_web = conv(to_information_web, value, key) # 'http://www.nösslachhütte.at/page9.php'
+        elif key == u'Telefonauskunft': sl.information_phone = conv(to_information_phone, value, key) # '+43-664-5487520 (Mitterer Alm)'
+        elif key == u'Bild': sl.image = conv(to_string, value, key)
+        elif key == u'In Übersichtskarte': sl.show_in_overview = conv(to_bool, value, key)
+        elif key == u'Forumid': sl.forum_id = conv(to_forum_id, value, key)
+        else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Rodelbahnbox: '%s' (mit Wert '%s')" % (key, value), value, None)
+    sl.under_construction = None
+    return sl
+
+
+def wrSleddingCache1_2_to_WrSleddingCache(wrSleddingCache1_2):
+    """Converts the old WrSleddingCache format (1.2) WrSleddingCache1_2
+    to the new format (1.3) WrSleddingCache."""
+    wrSleddingCache = model.WrSleddingCache() # Create an object in the new format
+    wrSleddingCache.page_id = wrSleddingCache1_2.page_id
+    wrSleddingCache.page_title = wrSleddingCache1_2.page_id
+    wrSleddingCache.position_latitude = wrSleddingCache1_2.position_latitude
+    wrSleddingCache.position_longitude = wrSleddingCache1_2.position_longitude
+    wrSleddingCache.top_latitude = None
+    wrSleddingCache.top_longitude = None
+    wrSleddingCache.top_elevation = wrSleddingCache1_2.height_top
+    wrSleddingCache.bottom_latitude = None
+    wrSleddingCache.bottom_longitude = None
+    wrSleddingCache.bottom_elevation = wrSleddingCache1_2.height_bottom
+    wrSleddingCache.length = wrSleddingCache1_2.length
+    wrSleddingCache.difficulty = None
+    if 'avalanches' in dir(wrSleddingCache1_2): wrSleddingCache.avalanches = wrSleddingCache1_2.avalanches
+    else: wrSleddingCache.avalanches = None
+    wrSleddingCache.operator = None
+    if wrSleddingCache1_2.public_transport is None: wrSleddingCache.public_transport = None
+    else: wrSleddingCache.public_transport = 6 if wrSleddingCache1_2.public_transport else 5
+    wrSleddingCache.walkup_time = wrSleddingCache1_2.walktime
+    if wrSleddingCache1_2.walkup_separate is None: wrSleddingCache.walkup_separate = None
+    wrSleddingCache.walkup_separate = 1.0 if wrSleddingCache1_2.walkup_separate else 0.0
+    wrSleddingCache.walkup_separate_comment = None
+    wrSleddingCache.lift = wrSleddingCache1_2.lift
+    if wrSleddingCache1_2.lift: wrSleddingCache.lift_details = "Ja"
+    else: wrSleddingCache.lift_details = None
+    if wrSleddingCache1_2.night_light is None: wrSleddingCache.night_light = None
+    else: wrSleddingCache.night_light = 1.0 if wrSleddingCache1_2.night_light else 0.0
+    wrSleddingCache.night_light_comment = None
+    wrSleddingCache.night_light_days = None
+    wrSleddingCache.night_light_days_comment = None
+    wrSleddingCache.sled_rental = wrSleddingCache1_2.sledge_rental
+    wrSleddingCache.sled_rental_comment = None
+    wrSleddingCache.cachet = None
+    wrSleddingCache.information_web = None
+    if wrSleddingCache1_2.information is None: wrSleddingCache.information_phone = None
+    else:
+        m = re.match('^([-\d/\+]{5,}) \((.+)\)', wrSleddingCache1_2.information)
+        if m is None: raise formencode.Invalid('PhoneInfo is invalid', value, None)
+        (phone, info) = m.groups()
+        # check phone
+        phone = wradmin.model.validators.AustrianPhoneNumber().to_python(phone)
+        # convert phone
+        c = formencode.national.InternationalPhoneNumber(default_cc=lambda: 43)
+        phone = c.to_python(phone)
+        wrSleddingCache.information_phone = '%s (%s)' % (phone, info)
+    wrSleddingCache.image = wrSleddingCache1_2.image
+    wrSleddingCache.show_in_overview = wrSleddingCache1_2.show_in_overview
+    wrSleddingCache.forum_id = wrSleddingCache1_2.forum_id
+    wrSleddingCache.under_construction = wrSleddingCache1_2.under_construction
+    return wrSleddingCache
+
+
+def wrSleddingCache_to_Rodelbahnbox(wrSleddingCache):
+    """Converts the WrSleddingCache class to the {{Rodelbahnbox}} representation.
+wrSleddingCache.cachet
+wrSleddingCache.forum_id
+wrSleddingCache.image
+wrSleddingCache.information_phone
+wrSleddingCache.information_web
+wrSleddingCache.lift
+wrSleddingCache.lift_details
+wrSleddingCache.night_light
+wrSleddingCache.night_light_comment
+wrSleddingCache.night_light_days
+wrSleddingCache.night_light_days_comment
+wrSleddingCache.show_in_overview
+wrSleddingCache.sled_rental
+wrSleddingCache.sled_rental_comment
+wrSleddingCache.under_construction
+    """
+    keys = []
+    values = []
+    keys.append(u'Position')
+    values.append(wradmin.model.validators.Geo().from_python((wrSleddingCache.position_latitude, wrSleddingCache.position_longitude)))
+    keys.append(u'Position oben')
+    values.append(wradmin.model.validators.Geo().from_python((wrSleddingCache.top_latitude, wrSleddingCache.top_longitude)))
+    keys.append(u'Höhe oben')
+    values.append(from_unsigned(wrSleddingCache.top_elevation))
+    keys.append(u'Position unten')
+    values.append(wradmin.model.validators.Geo().from_python((wrSleddingCache.bottom_latitude, wrSleddingCache.bottom_longitude)))
+    keys.append(u'Höhe unten')
+    values.append(from_unsigned(wrSleddingCache.bottom_elevation))
+    keys.append(u'Länge')
+    values.append(from_unsigned(wrSleddingCache.length))
+    keys.append(u'Schwierigkeit')
+    values.append(model.validators.GermanDifficulty().from_python(wrSleddingCache.difficulty))
+    keys.append(u'Lawinen')
+    values.append(model.validators.GermanAvalanches().from_python(wrSleddingCache.avalanches))
+    keys.append(u'Betreiber')
+    values.append(formencode.validators.String().from_python(wrSleddingCache.operator))
+    keys.append(u'Öffentliche Anreise')
+    values.append(model.validators.GermanPublicTransport().from_python(wrSleddingCache.public_transport))
+    keys.append(u'Gehzeit')
+    values.append(from_unsigned(wrSleddingCache.walkup_time))
+    keys.append(u'Aufstieg getrennt')
+    v = model.validators.GermanTristateFloat().from_python(wrSleddingCache.walkup_separate)
+    if not wrSleddingCache.walkup_separate_comment is None: v += ' (%s)' % wrSleddingCache.walkup_separate_comment
+    values.append(v)
+    
+    b = u"""
+| Aufstiegshilfe       = Gondel (unterer Teil)
+| Beleuchtungsanlage   = Ja
+| Beleuchtungstage     = 3 (Montag, Mittwoch, Freitag)
+| Rodelverleih         = Ja (Talstation Serlesbahnan)
+| Gütesiegel           = Tiroler Naturrodelbahn-Gütesiegel 2009 mittel
+| Webauskunft          = http://www.nösslachhütte.at/page9.php
+| Telefonauskunft      = +43-664-5487520 (Mitterer Alm)
+| Bild                 = Rodelbahn_Mitterer_Alm_04.jpg
+| In Übersichtskarte   = Ja
+| Forumid              = 33
+}}
+    """
+    
+    c = u"""
+    keys.append(u'Betreiber')
+    values.append(formencode.validators.String().from_python(wrInnCache.operator))
+    keys.append(u'Sitzplätze')
+    values.append(from_unsigned(wrInnCache.seats))
+    keys.append(u'Übernachtung')
+    values.append(from_overnight(wrInnCache.overnight, wrInnCache.overnight_comment))
+    keys.append(u'Rauchfrei')
+    values.append(wradmin.model.validators.GermanTristate.from_python((wrInnCache.nonsmoker_area, wrInnCache.smoker_area)))
+    keys.append(u'Rodelverleih')
+    values.append(from_sled_rental_inn(wrInnCache.sled_rental, wrInnCache.sled_rental_comment))
+    keys.append(u'Handyempfang')
+    values.append(formencode.validators.String().from_python(wrInnCache.mobile_provider))
+    keys.append(u'Homepage')
+    values.append(formencode.validators.String().from_python(wrInnCache.homepage))
+    keys.append(u'E-Mail')
+    values.append(formencode.validators.String().from_python(wrInnCache.email_list))
+    keys.append(u'Telefon')
+    values.append(formencode.validators.String().from_python(wrInnCache.phone_list))
+    keys.append(u'Bild')
+    values.append(formencode.validators.String().from_python(wrInnCache.image))
+    keys.append(u'Rodelbahnen')
+    values.append(formencode.validators.String().from_python(wrInnCache.sledding_list))
+    """
+    result = [u'{{Rodelbahnbox']
+    for i in xrange(len(keys)): result.append(u'| %-20s = %s' % (keys[i], values[i]))
+    result.append('}}\n')
+    return '\n'.join(result)
+
+
+def wikipage_to_wrinncache1_2(page_id, page_title, page_text):
+    """Converts a wiki page about an inn to an wradmin.model.WrInnCache1_2 class
+    that can be inserted to the wradmin.model.wrinncache1_2_table.
+    It uses only text operations and does not query or update the database.
+    It needs the wiki page id, the wiki page title and the page text ("old_text") as they come from the database."""
+    inn = model.WrInnCache1_2()
+    inn.page_id = page_id
+    inn.page_title = to_title(page_title)
+    
+    # Match Gasthausbox
+    wikitext = page_text
+    regexp = re.compile(u"\{\{(Gasthausbox[^\}]*)\}\}", re.DOTALL)
+    match = regexp.search(wikitext)
+    if not match:
+        raise Exception(u"No 'Gasthausbox' found")
+    box = match.group(1)
+    
+    # Process Gashausbox
+    for property in box.split('|'):
+        property = property.strip()
+        if property == u'Gasthausbox': continue
+        key_value = property.split('=')
+        if len(key_value) != 2:
+            raise Exception(u"Property '%s' has unexpected format" % key_value)
+        key = key_value[0].strip()
+        value = key_value[1].strip()
+        if key == u'Gasthausnummer': pass
+        elif key == u'E-Mail': inn.email = conv(to_email, value, u'E-Mail')
+        elif key == u'Homepage': inn.homepage = conv(to_url, value, u'Homepage')
+        elif key == u'Höhe': inn.height = conv(to_unsigned, value, u'Höhe')
+        elif key == u'Bild': inn.image = conv(to_string, value, key)
+        elif key == u'Position': inn.position_latitude, inn.position_longitude = conv(to_geo, value, u'Position') # '47.583333 N 15.75 E'
+        elif key == u'Telefon (Festnetz)': inn.phone = conv(to_phone, value, u'Telefon (Festnetz)')
+        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 formencode.Invalid(u"Unbekannte Eigenschaft der Gasthausbox: '%s' (mit Wert '%s')" % (key, value), value, None)
+    inn.under_construction = None
+    return inn
+
+
+def wikipage_to_wrinncache(wiki_page):
+    """Converts a inn wiki page (wradmin.model.page_table) to a wrinncache database record
+    (wradmin.model.wrinncache_table)."""
+    inn = model.WrInnCache()
+    inn.page_id = inn_wiki.page_id
+    inn.page_title = to_title(inn_wiki.page_title)
+    
+    # Match Gasthausbox
+    wikitext = inn_wiki.old_text
+    regexp = re.compile(u"\{\{(Gasthausbox[^\}]*)\}\}", re.DOTALL)
+    match = regexp.search(wikitext)
+    if not match:
+        raise Exception(u"No 'Gasthausbox' found")
+    box = match.group(1)
+    
+    # Process Gashausbox
+    for property in box.split('|'):
+        property = property.strip()
+        if property == u'Gasthausbox': continue
+        key_value = property.split('=')
+        if len(key_value) != 2:
+            raise Exception(u"Property '%s' has unexpected format" % key_value)
+        key = key_value[0].strip()
+        value = key_value[1].strip()
+        if key == u'Position': (inn.position_latitude, inn.position_longitude) = conv(to_geo, value, key) # '47.583333 N 15.75 E'
+        elif key == u'Höhe': inn.position_elevation = conv(to_unsigned, value, key)
+        elif key == u'Operator': inn.operator = conv(to_string, value, key)
+        elif key == u'Sitzplätze': inn.seats = conv(to_unsigned, value, key)
+        elif key == u'Übernachtung': inn.overnight, inn.overnight_comment = conv(to_overnight, value, key)
+        elif key == u'Rauchfrei': inn.nonsmoker_area, inn.smoker_area = conv(to_tristate, value, key)
+        elif key == u'Rodelverleih': inn.sled_rental, inn.sled_rental_comment = conv(to_sled_rental_inn, value, key)
+        elif key == u'Handyempfang': inn.mobile_provider = conv(to_mobile_provider, value, key)
+        elif key == u'Homepage': inn.homepage = conv(to_information_web, value, key)
+        elif key == u'E-Mail': inn.email, inn.email_comment, inn.email_list = conv(to_email_list, value, key)
+        elif key == u'Telefon': inn.phone, inn.phone_comment, inn.phone_list = conv(to_phone_list, value, key)
+        elif key == u'Bild': inn.image = conv(to_string, value, key)
+        elif key == u'Rodelbahnen': inn.sledding_list = conv(to_sledding_list, value, key)
+        else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Gasthausbox: '%s' (mit Wert '%s')" % (key, value), value, None)
+    inn.under_construction = None
+    return inn
+
+
+def wrInnCache1_2_to_WrInnCache(wrInnCache1_2):
+    """Converts the old WrInnCache format to the new format."""
+    wrInnCache = model.WrInnCache() # Create an object in the new format
+    wrInnCache.page_id = wrInnCache1_2.page_id
+    wrInnCache.page_title = wrInnCache1_2.page_id
+    wrInnCache.position_latitude = wrInnCache1_2.position_latitude
+    wrInnCache.position_longitude = wrInnCache1_2.position_longitude
+    wrInnCache.position_elevation = wrInnCache1_2.height
+    wrInnCache.operator = None
+    wrInnCache.seats = None
+    wrInnCache.overnight = None
+    wrInnCache.overnight_comment = None
+    wrInnCache.smoker_area = wrInnCache1_2.smoker_area
+    wrInnCache.nonsmoker_area = wrInnCache1_2.nonsmoker_area
+    wrInnCache.sled_rental = None
+    wrInnCache.sled_rental_comment = None
+    wrInnCache.mobile_provider = None
+    wrInnCache.homepage = wrInnCache1_2.homepage
+    wrInnCache.email = wrInnCache1_2.email
+    wrInnCache.email_comment = None
+    wrInnCache.email_list = wrInnCache1_2.email
+    phone_list = []
+    c = formencode.national.InternationalPhoneNumber(default_cc=lambda: 43)
+    if not wrInnCache1_2.phone is None: phone_list.append(c.to_python(wrInnCache1_2.phone))
+    if not wrInnCache1_2.mobile_phone is None: phone_list.append(c.to_python(wrInnCache1_2.mobile_phone))
+    if len(phone_list) >= 1: wrInnCache.phone = phone_list[0]
+    else: wrInnCache.phone = None
+    wrInnCache.phone_comment = None
+    wrInnCache.phone_list = "; ".join(phone_list)
+    wrInnCache.image = wrInnCache1_2.image
+    wrInnCache.sledding_list = None
+    wrInnCache.under_construction = wrInnCache1_2.under_construction
+    return wrInnCache
+
+
+def wrInnCache_to_Gasthausbox(wrInnCache):
+    """Converts the WrInnCache class to the {{Gasthausbox}} representation."""
+    keys = []
+    values = []
+    keys.append(u'Position')
+    values.append(wradmin.model.validators.Geo().from_python((wrInnCache.position_latitude, wrInnCache.position_longitude)))
+    keys.append(u'Höhe')
+    values.append(from_unsigned(wrInnCache.position_elevation))
+    keys.append(u'Betreiber')
+    values.append(formencode.validators.String().from_python(wrInnCache.operator))
+    keys.append(u'Sitzplätze')
+    values.append(from_unsigned(wrInnCache.seats))
+    keys.append(u'Übernachtung')
+    values.append(from_overnight(wrInnCache.overnight, wrInnCache.overnight_comment))
+    keys.append(u'Rauchfrei')
+    values.append(wradmin.model.validators.GermanTristate.from_python((wrInnCache.nonsmoker_area, wrInnCache.smoker_area)))
+    keys.append(u'Rodelverleih')
+    values.append(from_sled_rental_inn(wrInnCache.sled_rental, wrInnCache.sled_rental_comment))
+    keys.append(u'Handyempfang')
+    values.append(formencode.validators.String().from_python(wrInnCache.mobile_provider))
+    keys.append(u'Homepage')
+    values.append(formencode.validators.String().from_python(wrInnCache.homepage))
+    keys.append(u'E-Mail')
+    values.append(formencode.validators.String().from_python(wrInnCache.email_list))
+    keys.append(u'Telefon')
+    values.append(formencode.validators.String().from_python(wrInnCache.phone_list))
+    keys.append(u'Bild')
+    values.append(formencode.validators.String().from_python(wrInnCache.image))
+    keys.append(u'Rodelbahnen')
+    values.append(formencode.validators.String().from_python(wrInnCache.sledding_list))
+    result = [u'{{Gasthausbox']
+    for i in xrange(len(keys)): result.append(u'| %-17s = %s' % (keys[i], values[i]))
+    result.append('}}\n')
+    return '\n'.join(result)
+
+
+
 # User management
 # ---------------
 
index f1839b0ab095855fbe454679e4d220437f835c09..29530118f3023c36dd8cfe310c7ee9039c29c885 100644 (file)
@@ -10,6 +10,9 @@ def init_model(engine):
     meta.engine = engine
 
 
+# Current table definition
+# - version 1.2
+# - version 1.3 (no changes)
 wrreport_table = sa.Table("wrreport", meta.metadata,
     sa.Column("id", types.Integer, primary_key=True),
     sa.Column("page_id", types.Integer, schema.ForeignKey('wrsleddingcache.page_id')),
@@ -32,7 +35,9 @@ wrreport_table = sa.Table("wrreport", meta.metadata,
     )
 
 
-wrsleddingcache_table =  sa.Table("wrsleddingcache", meta.metadata,
+# Old table definition
+# - version 1.2
+wrsleddingcache_table1_2 =  sa.Table("wrsleddingcache1_2", meta.metadata,
     sa.Column("page_id", types.Integer, primary_key=True),
     sa.Column("page_title", types.Unicode(255)),
     sa.Column("length", types.Integer),
@@ -54,7 +59,48 @@ wrsleddingcache_table =  sa.Table("wrsleddingcache", meta.metadata,
     )
 
 
-wrinncache_table =  sa.Table("wrinncache", meta.metadata,
+# Current table definition
+# - version 1.3 (changes made from version 1.2)
+wrsleddingcache_table =  sa.Table("wrsleddingcache", meta.metadata,
+    sa.Column("page_id", types.Integer, primary_key=True),
+    sa.Column("page_title", types.Unicode(255)),
+    sa.Column("position_latitude", types.Float),
+    sa.Column("position_longitude", types.Float),
+    sa.Column("top_latitude", types.Float),
+    sa.Column("top_longitude", types.Float),
+    sa.Column("top_elevation", types.Integer),
+    sa.Column("bottom_latitude", types.Float),
+    sa.Column("bottom_longitude", types.Float),
+    sa.Column("bottom_elevation", types.Integer),
+    sa.Column("length", types.Integer),
+    sa.Column("difficulty", types.Integer),
+    sa.Column("avalanches", types.Integer),
+    sa.Column("operator", types.Unicode(255)),
+    sa.Column("public_transport", types.Integer),
+    sa.Column("walkup_time", types.Integer),
+    sa.Column("walkup_separate", types.Float),
+    sa.Column("walkup_separate_comment", types.Unicode(255)),
+    sa.Column("lift", types.Boolean),
+    sa.Column("lift_details", types.Unicode(255)),
+    sa.Column("night_light", types.Float),
+    sa.Column("night_light_comment", types.Unicode(255)),
+    sa.Column("night_light_days", types.Integer),
+    sa.Column("night_light_days_comment", types.Unicode(255)),
+    sa.Column("sled_rental", types.Boolean),
+    sa.Column("sled_rental_comment", types.Unicode(255)),
+    sa.Column("cachet", types.Unicode(255)),
+    sa.Column("information_web", types.Unicode(255)),
+    sa.Column("information_phone", types.Unicode(255)),
+    sa.Column("image", types.Unicode(255)),
+    sa.Column("show_in_overview", types.Boolean),
+    sa.Column("forum_id", types.Integer),
+    sa.Column("under_construction", types.Boolean),
+    )
+
+
+# Old table definition
+# - version 1.2
+wrinncache_table1_2 =  sa.Table("wrinncache1_2", meta.metadata,
     sa.Column("page_id", types.Integer, primary_key=True),
     sa.Column("page_title", types.Unicode(255)),
     sa.Column("height", types.Integer),
@@ -71,6 +117,35 @@ wrinncache_table =  sa.Table("wrinncache", meta.metadata,
     )
 
 
+# Current table definition
+# - version 1.3 (changes made from version 1.2)
+wrinncache_table =  sa.Table("wrinncache", meta.metadata,
+    sa.Column("page_id", types.Integer, primary_key=True),
+    sa.Column("page_title", types.Unicode(255)),
+    sa.Column("position_latitude", types.Float),
+    sa.Column("position_longitude", types.Float),
+    sa.Column("position_elevation", types.Integer),
+    sa.Column("seats", types.Integer),
+    sa.Column("overnight", types.Boolean),
+    sa.Column("overnight_comment", types.Unicode(255)),
+    sa.Column("smoker_area", types.Boolean),
+    sa.Column("nonsmoker_area", types.Boolean),
+    sa.Column("sled_rental", types.Boolean),
+    sa.Column("sled_rental_comment", types.Unicode(255)),
+    sa.Column("mobile_provider", types.Unicode),
+    sa.Column("homepage", types.Unicode(255)),
+    sa.Column("email", types.Unicode(255)),
+    sa.Column("email_comment", types.Unicode(255)),
+    sa.Column("email_list", types.Unicode),
+    sa.Column("phone", types.Unicode(30)),
+    sa.Column("phone_comment", types.Unicode(255)),
+    sa.Column("phone_list", types.Unicode),
+    sa.Column("image", types.Unicode(255)),
+    sa.Column("sledding_list", types.Unicode),
+    sa.Column("under_construction", types.Boolean),
+    )
+
+
 page_table = sa.Table("page", meta.metadata,
     sa.Column("page_id", types.Integer, primary_key=True),
     sa.Column("page_namespace", types.Integer, nullable=False),
@@ -120,16 +195,35 @@ class WrReport(object):
     pass
 
 
+# Old version (not mapped)
+class WrSleddingCache1_2(object):
+    pass
+
+
 class WrSleddingCache(object):
     pass
 
 
+# Old version (not mapped)
+class WrInnCache1_2(object):
+    pass
+
+
 class WrInnCache(object):
     pass
 
 
+# Page (not mapped)
+class Page(object):
+    pass
+
+
 orm.mapper(WrReport, wrreport_table)
 # We could add a relation but we don't need it yet:
 # orm.mapper(WrSleddingCache, wrsleddingcache_table, properties = {'reports': orm.relation(WrReport, backref='sledding')})
 orm.mapper(WrSleddingCache, wrsleddingcache_table)
 orm.mapper(WrInnCache, wrinncache_table)
+
+# Old tables
+orm.mapper(WrSleddingCache1_2, wrsleddingcache_table1_2)
+orm.mapper(WrInnCache1_2, wrinncache_table1_2)
index 9f555e854481166ede3aec4578630655ce54b212..e733948a192f58ed9dd21c65e88b59993b3d52da 100644 (file)
@@ -59,7 +59,7 @@ class DateConverter(GenericDateTimeConverter):
         GenericDateTimeConverter.__init__(self, '%Y-%m-%d', **keywords)
     
     def _to_python(self, value, state):
-        GenericDateTimeConverter._to_python(self, value, state).date()
+        return GenericDateTimeConverter._to_python(self, value, state).date()
 
 
 class GermanTristate(formencode.FancyValidator):
@@ -206,6 +206,7 @@ class MultiGeo(formencode.FancyValidator):
         return "\n".join(result)
 
 
+# deprecated
 class AustrianPhoneNumber(formencode.FancyValidator):
     """
     Validates and converts phone numbers to +##/###/####### or +##/###/#######-### (having an extension)
@@ -252,6 +253,7 @@ class AustrianPhoneNumber(formencode.FancyValidator):
         return '+%s/%s-%s' % (country, phone, extension)
 
 
+# Deprecated
 class PhoneInfo(formencode.FancyValidator):
     "Validates a info of the form '0644/1234567 (Schnee Alm)'"
     messages = {'infoFormat': "'%%(value)s' is no valid format, please use a form like '0644/1234567 (Schnee Alm)'"}
@@ -266,3 +268,222 @@ class PhoneInfo(formencode.FancyValidator):
         phone = AustrianPhoneNumber().to_python(phone)
         
         return "%s (%s)" % (phone, info)
+
+
+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')"""
+    
+    def __init__(self, comment_is_optional=True):
+        self.comment_is_optional = comment_is_optional
+    
+    def _to_python(self, value, state):
+        self.assert_string(value, state)
+        if value == u'': return None
+        left = value.find('(')
+        right = value.rfind(')')
+        if left < 0 and right < 0:
+            if not comment_is_optional: raise formencode.Invalid(u'Mandatory comment not present', value, state)
+            return value, None
+        elif left >= 0 and right >= 0 and left < right:
+            return value[:left].strip(), value[left+1:right].strip()
+        else: raise formencode.Invalid(u'Invalid format', value, state)
+
+    def from_python(self, value):
+        assert len(value) == 2
+        if value[0] is None:
+            assert value[1] == None
+            return u''
+        if value[1] is None:
+            return value[0]
+        return u'%s (%s)' % (value[0], value[1])
+
+
+class ValueCommentList(formencode.FancyValidator):
+    """A value-comment list looks like one of the following lines:
+        value
+        value (optional comment)
+        value1; value2
+        value1; value2 (optional comment)
+        value1 (optional comment1); value2 (optional comment2); value3 (otional comment3)
+        value1 (optional comment1); value2 (optional comment2); value3 (otional comment3)
+    This function returns the value-comment list as list of tuples:
+        [(u'value1', u'comment1'), (u'value2', None)]
+    If no comment is present, None is specified.
+    For an empty string, None is returned."""
+    messages = {'infoFormat': "'%%(value)s' is no valid format, please use a form like 'value1 (optional comment1); value2 (optional comment2)'"}
+    
+    def _to_python(self, value, state):
+        self.assert_string(value, state)
+        value_options = [s.strip() for s in value.split(';')]
+        result = []
+        for value_option in value_options:
+            left = value_option.find('(')
+            right = value_option.rfind(')')
+            if left < 0 and right < 0:
+                result.append((value_option, None))
+            elif left >= 0 and right >= 0 and left < right:
+                result.append((value_option[:left].strip(), value_option[left+1:right].strip()))
+            else: raise formencode.Invalid(self.message('infoFormat', state) % {'value': value}, value, state)
+        return result
+
+    def _from_python(self, value, state):
+        result = []
+        for v, c in value:
+            if c is None: result.append(v)
+            else: result.append('%s (%s)' % (v, c))
+        return "; ".join(result)
+
+
+class GermanDifficulty(formencode.FancyValidator):
+    """Converts the difficulty represented in a number from 1 to 3 (or None)
+    to a German representation:
+    u''       <=> None
+    u'leicht' <=> 1
+    u'mittel' <=> 2
+    u'schwer' <=> 3"""
+    dc = formencode.validators.DictConverter({u'leicht': 1, u'mittel': 2, u'schwer': 3})
+    
+    def _to_python(self, value, state):
+        """Value has to be one of u'', u'leicht', u'mittel' or u'schwer':
+        u''       => None
+        u'leicht' => 1
+        u'mittel' => 2
+        u'schwer' => 3"""
+        self.assert_string(value, state)
+        return self.dc.to_python(value)
+    
+    def from_python(self, value):
+        """value has to be one of None, 1, 2, 3:
+        None => u''
+        1    => u'leicht'
+        2    => u'mittel'
+        3    => u'schwer'"""
+        if value is None: return u''
+        return self.dc.from_python(value)
+
+
+class GermanAvalanches(formencode.FancyValidator):
+    """Converts the avalanches property represented as number from 1 to 4 (or None)
+    to a German representation:
+    u''             <=> None
+    u'kaum'         <=> 1
+    u'selten'       <=> 2
+    u'gelegentlich' <=> 3
+    u'häufig'       <=> 4"""
+    dc = formencode.validators.DictConverter({u'kaum': 1, u'selten': 2, u'gelegentlich': 3, u'häufig': 4})
+    
+    def _to_python(self, value, state):
+        """value has to be one of u'', u'kaum', u'selten', u'gelegentlich', u'häufig':
+        u''             => None
+        u'kaum'         => 1
+        u'selten'       => 2
+        u'gelegentlich' => 3
+        u'häufig'       => 4"""
+        self.assert_string(value, state)
+        return self.dc.to_python(value)
+    
+    def from_python(self, value):
+        """value has to be one of None, 1, 2, 3, 4:
+        None => u''
+        1    => u'kaum'
+        2    => u'selten'
+        3    => u'gelegentlich'
+        4    => u'häufig'"""
+        if value is None: return u''
+        return self.dc.from_python(value)
+
+
+class GermanPublicTransport(formencode.FancyValidator):
+    """Converts the public_transport property represented as number from 1 to 6 (or None)
+    to a German representation:
+    u''            <=> None
+    u'Sehr gut'    <=> 1
+    u'Gut'         <=> 2
+    u'Mittelmäßig' <=> 3
+    u'Schlecht'    <=> 4
+    u'Nein'        <=> 5
+    u'Ja'          <=> 6"""
+    dc = formencode.validators.DictConverter({u'Sehr gut': 1, u'Gut': 2, u'Mittelmäßig': 3, u'Schlecht': 4, u'Nein': 5, u'Ja': 6})
+
+    def _to_python(self, value, state):
+        """value has to be one of u'', u'Sehr gut', u'Gut', u'Mittelmäßig', u'Schlecht', u'Nein', u'Ja':
+        u''            => None
+        u'Sehr gut'    => 1
+        u'Gut'         => 2
+        u'Mittelmäßig' => 3
+        u'Schlecht'    => 4
+        u'Nein'        => 5
+        u'Ja'          => 6"""
+        self.assert_string(value, state)
+        return self.dc.to_python(value)
+    
+    def from_python(self, value):
+        """value has to be one of None, 1, 2, 3, 4, 5, 6:
+        None => u''            
+        1    => u'Sehr gut'
+        2    => u'Gut'
+        3    => u'Mittelmäßig'
+        4    => u'Schlecht'
+        5    => u'Nein'
+        6    => u'Ja'"""
+        if value is None: return u''
+        return self.dc.from_python(value)
+
+
+class GermanTristateFloat(formencode.FancyValidator):
+    """Converts the a property with the possible values 0.0, 0.5, 1.0 or None
+    to a German text:
+    u''          <=> None
+    u'Ja'        <=> 1.0
+    u'Teilweise' <=> 0.5
+    u'Nein'      <=> 0.0"""
+    dc = formencode.validators.DictConverter({u'Ja': 1.0, u'Teilweise': 0.5, u'Nein': 0.0})
+
+    def _to_python(self, value, state):
+        """value has to be one of u'', u'Ja', u'Teilweise', u'Nein':
+        u''          => None
+        u'Ja'        => 1.0
+        u'Teilweise' => 0.5
+        u'Nein'      => 0.0"""
+        self.assert_string(value, state)
+        return self.dc.to_python(value)
+    
+    def from_python(self, value):
+        """value has to be one of None, 0.0, 0.5, 1.0:
+        None => u''
+        0.0    => u'Nein'
+        0.5    => u'Teilweise'
+        1.0    => u'Ja'"""
+        if value is None: return u''
+        return self.dc.from_python(value)
+
+
+class GermanTristateFloatComment(formencode.FancyValidator):
+    """Converts the a property with the possible values 0.0, 0.5, 1.0 or None and an optional comment
+    in parenthesis to a German text:
+    u''                  <=> (None, None
+    u'Ja'                <=> (1.0,  None
+    u'Teilweise'         <=> (0.5,  None
+    u'Nein'              <=> (0.0,  None
+    u'Ja (aber schmal)'  <=> (1.0,  u'aber schmal')
+    u'Teilweise (oben)'  <=> (0.5,  u'oben')
+    u'Nein (aber breit)' <=> (0.0,  u'aber breit')
+    """
+    tf = GermanTristateFloat()
+
+    def _to_python(self, value, state):
+        self.assert_string(value, state)
+        return self.dc.to_python(value)
+    
+    def from_python(self, value):
+        """value has to be one of None, 0.0, 0.5, 1.0:
+        None => u''
+        0.0    => u'Nein'
+        0.5    => u'Teilweise'
+        1.0    => u'Ja'"""
+        if value is None: return u''
+        return self.dc.from_python(value)
+
index b9ffe04a97a1f44e1eaefa9dfc130dc5598ce89e..eb77fe898e6b1499d7e88ad9d03ee51c23c566ab 100644 (file)
@@ -50,7 +50,7 @@
         <td>${h.bool(s.walkup_separate)}</td>
         <td>${h.bool(s.lift)}</td>
         <td>${h.bool(s.night_light)}</td>
-        <td>${h.bool(s.sledge_rental)}</td>
+        <td>${h.bool(s.sled_rental)}</td>
         <td>${h.bool(s.public_transport)}</td>
         <td><small>${s.image}</small></td>
         <td>${s.position_latitude}</td>
index 10fa68579afa9602824f6c2ee130ad973e99a66f..52d7da4fd9d27f3263e9a526f6c263712c4d2790 100644 (file)
@@ -53,7 +53,7 @@
     </tr>
     <tr>
         <th>Rodelverleih</th>
-        <td>${h.bool(c.sledding.sledge_rental)}</td>
+        <td>${h.bool(c.sledding.sled_rental)}</td>
     </tr>
     <tr>
         <th>Öffentliche Anreise</th>
index dc1992fa45f80c1723cee531fbc3e9ab3a5fde4f..05147b068d749371a220e16f17d6ddcffe8e92e6 100644 (file)
@@ -14,7 +14,7 @@
 
 <h2>WRGPX-Werkzeug</h2>
 
-<p><strong>Achtung: Da das WRGPX Format noch in Arbeit ist, ist diese Seite natürlich auch noch nicht fertig!</strong><p>
+<p><strong>Achtung: Da das WRGPX Format noch in Arbeit ist, ist diese Seite natürlich auch noch nicht fertig!</strong></p>
 
 <py:if test="not c.validated">
 <p>WRGPX steht für "Winterrodeln GPX". Hier können Sie eine .gpx Datei auf ihre Gültigkeit untersuchen.</p>
index c764688d3434a178fcd279735ae2749f1ae20f6f..df55e02faad68d1bb6f7166a48487562a1bed848 100644 (file)
@@ -1,4 +1,117 @@
+#!/usr/bin/python2.5
+# -*- coding: iso-8859-15 -*-
+# $Id$
 import wradmin.lib
+import wradmin.model
+
+
+def test_wikipage_to_wrsleddingcache1_2():
+    wiki_page = wradmin.model.Page()
+    wiki_page.page_id = 7
+    wiki_page.page_title = u"Kemater Alm"
+    wiki_page.old_text = u"""
+Text above
+{{Rodelbahnbox
+| Bild                 = Rodelbahn_Mitterer_Alm_04.jpg
+| Position             = 47.203959 N 11.308052 E
+| Länge                = 3500
+| Gehzeit              = 90
+| Höhe oben            = 2000
+| Höhe unten           = 1200
+| Aufstieg getrennt    = Ja
+| Lift                 = Nein
+| Beleuchtung          = Nein
+| Rodelverleih         = Ja
+| Öffentliche Anreise  = Nein
+| Lawinengefahr        = kaum
+| Auskunft             = 0664/5487520 (Mitterer Alm)
+| In Übersichtskarte   = Ja
+}}
+Text below"""
+    sledding_cache = wradmin.lib.mediawiki.wikipage_to_wrsleddingcache1_2(wiki_page)
+    assert sledding_cache.page_id == 7
+    assert sledding_cache.page_title == u"Kemater Alm"
+    assert sledding_cache.length == 3500
+    assert sledding_cache.walktime == 90
+    assert sledding_cache.height_top == 2000
+    assert sledding_cache.height_bottom == 1200
+    assert sledding_cache.walkup_separate == True
+    assert sledding_cache.lift == False
+    assert sledding_cache.night_light == False
+    assert sledding_cache.sledge_rental == True
+    assert sledding_cache.public_transport == False
+    assert sledding_cache.image == u"Rodelbahn_Mitterer_Alm_04.jpg"
+    assert sledding_cache.position_latitude == 47.203959
+    assert sledding_cache.position_longitude == 11.308052
+    assert sledding_cache.information == u"+43/664/5487520 (Mitterer Alm)"
+    # assert sledding_cache.forum_id
+    # assert sledding_cache.under_construction
+    assert sledding_cache.show_in_overview == True
+
+
+def test_wikipage_to_wrsleddingcache():
+    wiki_page = wradmin.model.Page()
+    wiki_page.page_id = 7
+    wiki_page.page_title = u"Kemater Alm"
+    wiki_page.old_text = u"""
+Text above
+{{Rodelbahnbox
+| Position             = 47.203959 N 11.308052 E
+| Position oben        = 
+| Höhe oben            = 1700
+| Position unten       = 
+| Höhe unten           = 1200
+| Länge                = 3500
+| Schwierigkeit        = mittel
+| Lawinen              = kaum
+| Betreiber            = Max Mustermann
+| Öffentliche Anreise  = Mittelmäßig
+| Gehzeit              = 90
+| Aufstieg getrennt    = Ja
+| Aufstiegshilfe       = Gondel (unterer Teil)
+| Beleuchtungsanlage   = Ja
+| Beleuchtungstage     = 3 (Montag, Mittwoch, Freitag)
+| Rodelverleih         = Ja (Talstation Serlesbahnan)
+| Gütesiegel           = Tiroler Naturrodelbahn-Gütesiegel 2009 mittel
+| Webauskunft          = http://www.nösslachhütte.at/page9.php
+| Telefonauskunft      = +43-664-5487520 (Mitterer Alm)
+| Bild                 = Rodelbahn_Mitterer_Alm_04.jpg
+| In Übersichtskarte   = Ja
+| Forumid              = 33
+}}
+Text below"""
+    sledding_cache = wradmin.lib.mediawiki.wikipage_to_wrsleddingcache(wiki_page)
+    assert sledding_cache.page_id == 7
+    assert sledding_cache.page_title == u"Kemater Alm"
+
+    assert sledding_cache.position_latitude == 47.203959
+    assert sledding_cache.position_longitude == 11.308052
+    assert sledding_cache.top_latitude == 47.203959
+    assert sledding_cache.top_longitude == 11.308052
+    assert sledding_cache.top_elevation == 2000
+    assert sledding_cache.bottom_latitude == 47.203959
+    assert sledding_cache.bottom_longitude == 11.308052
+    assert sledding_cache.bottom_elevation == 1200
+
+    assert sledding_cache.length == 3500
+    assert sledding_cache.walktime == 90
+    assert sledding_cache.walkup_separate == 1.0
+    sa.Column("walkup_separate_comment", types.Unicode(255)),    
+    assert sledding_cache.lift == False
+    sa.Column("lift_details", types.Unicode(255)),
+    assert sledding_cache.night_light == 1.0
+    sa.Column("night_light_days", types.Integer),
+    sa.Column("night_light_days_comment", types.Unicode(255)),
+    assert sledding_cache.sled_rental == True
+    assert sledding_cache.public_transport == 3
+    assert sledding_cache.avalanche = 1
+    assert sledding_cache.image == u"Rodelbahn_Mitterer_Alm_04.jpg"
+    assert sledding_cache.information == u"+43/664/5487520 (Mitterer Alm)"
+    assert sledding_cache.forum_threadid = 33
+    assert sledding_cache.show_in_overview == True
+
+    # assert sledding_cache.under_construction
+
 
 def test_mediawiki_users():
     users = wradmin.lib.mediawiki.MediaWikiUsers(True)
index 01ca6cf1fd25ff41e5c7be6674abba302fe10ca0..96ca739969cfef4ed8dececa4c3720b582890a26 100644 (file)
@@ -72,4 +72,13 @@ def test_PhoneInfo():
             v.to_python(n) # has to throw an exception
             assert False, u"The telephone info '%s' should throw an exception." % n
         except formencode.Invalid: pass        
-    
\ No newline at end of file
+
+def test_ValueCommentList():
+    v = wradmin.model.validators.ValueCommentList()
+    assert v.to_python('abc') == [('abc', None)]
+    assert v.to_python(u'abc def') == [(u'abc def', None)]
+    assert v.to_python('value (comment)') == [('value', 'comment')]
+    assert v.to_python(u'value (comment)') == [(u'value', u'comment')]
+    assert v.to_python('value1 (comment); value2') == [('value1', 'comment'), ('value2', None)]
+    assert v.to_python('value1 (comment1); value2; value3 (comment3)') == [('value1', 'comment1'), ('value2', None), ('value3', 'comment3')]
+    assert v.to_python('value1 (comment1); value2 (test (not easy))') == [('value1', 'comment1'), ('value2', 'test (not easy)')]
\ No newline at end of file