Implemented function update_wrmapcache.
authorphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Sun, 3 Jul 2011 18:48:11 +0000 (18:48 +0000)
committerphilipp <philipp@7aebc617-e5e2-0310-91dc-80fb5f6d2477>
Sun, 3 Jul 2011 18:48:11 +0000 (18:48 +0000)
git-svn-id: http://www.winterrodeln.org/svn/servermediawiki/trunk/wrpylib@860 7aebc617-e5e2-0310-91dc-80fb5f6d2477

setup.py
wrpylib/mwmarkup.py
wrpylib/wrmwcache.py

index f3cde2171a6cf1185a6072f206652bd18ee45ee6..534cab975fec34088a2ddda00ba17661fe5b5bb5 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from setuptools import setup
 
 setup(name='wrpylib',
-    version='0.0.12',
+    version='0.0.13',
     description='Winterrodeln Python Library',
     author='Philipp Spitzer',
     author_email='philipp.spitzer@winterrodeln.org',
index 79df791cefd69ebd622fedb8fa94329253dba4aa..88f8add9c055cc1af1a5197224439be0e41e51c2 100644 (file)
@@ -10,6 +10,7 @@ that convinced me. However, here are the links:
 * mwlib http://code.pediapress.com/wiki/wiki
 """
 import re
+import xml.etree.ElementTree
 
 
 def find_template(wikitext, template_title):
@@ -101,3 +102,110 @@ def create_template(template_title, anonym_params=[], named_param_keys=[], named
         parts.append(key + equal_char + named_param_values[i])
     return pipe_char.join(parts) + end_char
 
+
+def parse_googlemap(wikitext):
+    """Parses the (unicode) u'<googlemap ...>content</googlemap>' of the googlemap extension
+    out of a page. If wikitext does not contain the googlemaps extension text None is returned.
+    If the googlemap contains invalid formatted lines, a RuntimeError is raised.
+
+    :param wikitext: wikitext containing the template. Example:
+
+    wikitext = '''
+    <googlemap version="0.9" lat="47.113291" lon="11.272337" zoom="15">
+    (Parkplatz)47.114958,11.266026
+    Parkplatz
+    
+    (Gasthaus) 47.114715, 11.266262, Alt Bärnbad (Gasthaus)
+    6#FF014E9A
+    47.114715,11.266262
+    47.114135,11.268381
+    47.113421,11.269322
+    47.11277,11.269979
+    47.112408,11.271119
+    </googlemap>
+    '''
+    :returns: the tuple (center, zoom, coords, paths).
+        center is the tuple (lon, lat) of the google maps or (None, None) if not provided
+        zoom is the google zoom level as integer or None if not provided
+        coords is a list of (lon, lat, symbol, title) tuples.
+        paths is a list of (style, coords) tuples.
+        coords is again a list of (lot, lat, symbol, title) tuples."""
+
+    def is_coord(line):
+        """Returns True if the line contains a coordinate."""
+        match = re.search('[0-9]{1,2}\.[0-9]+, ?[0-9]{1,2}\.[0-9]+', line)
+        return not match is None
+
+    def is_path(line):
+        """Returns True if the line contains a path style definition."""
+        match = re.match('[0-9]#[0-9a-fA-F]{8}', line)
+        return not match is None
+
+    def parse_coord(line):
+        """Returns (lon, lat, symbol, title). If symbol or text is not present, None is returned."""
+        match = re.match(u'\(([^)]+)\) ?([0-9]{1,2}\.[0-9]+), ?([0-9]{1,2}\.[0-9]+),(.*)', line)
+        if not match is None: return (float(match.group(3)), float(match.group(2)), match.group(1), match.group(4))
+        match = re.match(u'\(([^)]+)\) ?([0-9]{1,2}\.[0-9]+), ?([0-9]{1,2}\.[0-9]+)', line)
+        if not match is None: return (float(match.group(3)), float(match.group(2)), match.group(1), None)
+        match = re.match(u'([0-9]{1,2}\.[0-9]+), ?([0-9]{1,2}\.[0-9]+),(.*)', line)
+        if not match is None: return (float(match.group(2)), float(match.group(1)), None, match.group(3))
+        match = re.match(u'([0-9]{1,2}\.[0-9]+), ?([0-9]{1,2}\.[0-9]+)', line)
+        if not match is None: return (float(match.group(2)), float(match.group(1)), None, None)
+        return RuntimeError(u'Could not parse line ' + line)
+
+    regexp = re.compile(u"(<googlemap[^>]*>)(.*)(</googlemap>)", re.DOTALL)
+    match = regexp.search(wikitext)
+    if match is None: return None
+    content = match.group(2)
+    gm = xml.etree.ElementTree.XML((match.group(1)+match.group(3)).encode('UTF8'))
+    zoom = gm.get('zoom')
+    lon = gm.get('lon')
+    lat = gm.get('lat')
+    if not zoom is None: zoom = int(zoom)
+    if not lon is None: lon = float(lon)
+    if not lat is None: lat = float(lat)
+    center = (lon, lat)
+
+    coords = []
+    paths = []
+    lines = content.split("\n")
+    i = 0
+    while i < len(lines):
+        line = lines[i].strip()
+        i += 1
+
+        # Skip whitespace
+        if len(line) == 0: continue
+
+        # Handle a path
+        if is_path(line):
+            match = re.match(u'([0-9]#[0-9a-fA-F]{8})', line)
+            style =  match.group(1)
+            local_coords = []
+            while i < len(lines):
+                line = lines[i].strip()
+                i += 1
+                if is_path(line):
+                    i -= 1
+                    break
+                if is_coord(line):
+                    lon, lat, symbol, title = parse_coord(line)
+                    local_coords.append((lon, lat, symbol, title))
+            paths.append((style, local_coords))
+            continue
+
+        # Handle a coordinate
+        if is_coord(line):
+            lon, lat, symbol, title = parse_coord(line)
+            coords.append((lon, lat, symbol, title))
+            while i < len(lines):
+                line = lines[i].strip()
+                i += 1
+                if is_path(line) or is_coord(line):
+                    i -= 1
+                    break
+            continue
+
+        raise RuntimeError(u'Unknown line syntax: ' + line)
+    return (center, zoom, coords, paths)
+
index 3e41c43fe863723197ddd8c3c271f90cf90be22e..f71566f9ef75a129099d511d1a17ae54e30767bc 100644 (file)
@@ -7,7 +7,7 @@ from xml.etree import ElementTree
 from sqlalchemy import schema
 from sqlalchemy.sql import select
 import formencode
-from wrpylib import mwdb, wrmwdb, wrmwmarkup
+from wrpylib import mwdb, wrmwdb, mwmarkup, wrmwmarkup
 
 
 class UpdateCacheError(RuntimeError):
@@ -150,3 +150,50 @@ def update_wrreportcache(connection, page_id=None):
     insert_row(connection, rowlist)
     transaction.commit()
 
+
+def update_wrmapcache(connection):
+    """Updates the wrmappointcache and wrmappathcache tables from the wiki. If convert errors occur, an UpdateCacheError exception
+    is raised. No other exception type should be raised under normal circumstances.
+    
+    >>> from sqlalchemy.engine import create_engine
+    >>> engine = create_engine('mysql://philipp@localhost:3306/winterrodeln_wiki?charset=utf8&use_unicode=0')
+    >>> update_wrmapcache(engine.connect())
+    """
+    metadata = schema.MetaData()
+    page = mwdb.page_table(metadata)
+    categorylinks = mwdb.categorylinks_table(metadata)
+    revision = mwdb.revision_table(metadata)
+    text = mwdb.text_table(metadata)
+
+    transaction = connection.begin()
+
+    # Query all sledruns
+    q = select([page, categorylinks, revision, text], (page.c.page_latest==revision.c.rev_id) & (text.c.old_id==revision.c.rev_text_id) & (categorylinks.c.cl_from==page.c.page_id) & (categorylinks.c.cl_to==u'Rodelbahn'))
+    sledrun_pages = connection.execute(q)
+    # Original SQL:
+    # sql = u"select page_id, rev_id, old_id, page_title, old_text, 'In_Arbeit' in (select cl_to from categorylinks where cl_from=page_id) as under_construction from page, revision, text, categorylinks where page_latest=rev_id and old_id=rev_text_id and cl_from=page_id and cl_to='Rodelbahn' order by page_title"
+    
+    # Delete all existing entries in wrmappointcache
+    # We rely on transactions MySQL InnoDB
+    connection.execute('delete from wrmappointcache')
+    connection.execute('delete from wrmappathcache')
+    
+    # Refill wrmappointcache and wrmappathcache tables
+    for sledrun_page in sledrun_pages:
+        try: 
+            result = mwmarkup.parse_googlemap(sledrun_page.old_text)
+            if not result is None:
+                center, zoom, coords, paths = result
+                for coord in coords:
+                    lon, lat, point_type, label = coord
+                    point_types = {u'Gasthaus': u'hut', u'Haltestelle': u'busstop', u'Parkplatz': u'carpark', u'Achtung': u'warning'}
+                    if not point_type is None:
+                        if not point_types.has_key(point_type): raise RuntimeError('Unknown point type {0}'.format(point_type))
+                        point_type = point_types[point_type]
+                        sql = 'insert into wrmappointcache (page_id, type, point, label) values (%s, %s, POINT(%s, %s), %s)'
+                        connection.execute(sql, (sledrun_page.page_id, point_type, lon, lat, None))
+        except RuntimeError as e:
+            error_msg = u"Error at sledrun '{0}': {1}".format(sledrun_page.page_title, unicode(e))
+            transaction.rollback()
+            raise UpdateCacheError(error_msg, sledrun_page.page_title, e)
+    transaction.commit()