Release of version 0.1.0.
[philipp/winterrodeln/wrpylib.git] / wrpylib / wrmwcache.py
1 #!/usr/bin/python2.7
2 # -*- coding: iso-8859-15 -*-
3 # $Id$
4 # $HeadURL$
5 """Contains functions that maintain/update the cache tables."""
6 from sqlalchemy import schema
7 from sqlalchemy.sql import select
8 import formencode
9 from wrpylib import mwdb, wrmwdb, mwmarkup, wrmwmarkup
10
11
12 class UpdateCacheError(RuntimeError):
13     pass
14
15
16 def update_wrsledruncache(connection):
17     """Updates the wrsledruncache table from the wiki. If convert errors occur, an UpdateCacheError exception
18     is raised. No other exception type should be raised under normal circumstances.
19     
20     >>> from sqlalchemy.engine import create_engine
21     >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=0')
22     >>> # see: https://sourceforge.net/tracker/?func=detail&aid=2837134&group_id=22307&atid=374932
23     >>> update_wrsledruncache(engine.connect())
24     """
25     metadata = schema.MetaData()
26     wrsledruncache = wrmwdb.wrsledruncache_table(metadata)
27     page = mwdb.page_table(metadata)
28     categorylinks = mwdb.categorylinks_table(metadata)
29     revision = mwdb.revision_table(metadata)
30     text = mwdb.text_table(metadata)
31
32     transaction = connection.begin()
33
34     # Query all sled runs
35     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'))
36     sledrun_pages = connection.execute(q)
37     # Original SQL:
38     # 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"
39     
40     # Delete all existing entries in wrsledruncache
41     # We rely on transactions MySQL InnoDB
42     connection.execute(wrsledruncache.delete())
43     
44     # Refill wrsledruncache table
45     for sledrun_page in sledrun_pages:
46         try: 
47             start, end, sledrun = wrmwmarkup.rodelbahnbox_to_sledrun(sledrun_page.old_text)
48             sledrun.page_id = sledrun_page.page_id
49             sledrun.page_title = sledrun_page.page_title
50             sledrun.under_construction = connection.execute(select([categorylinks], (categorylinks.c.cl_from==sledrun_page.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
51             connection.execute(wrsledruncache.insert(sledrun.__dict__))
52         except (RuntimeError, formencode.Invalid) as e:
53             transaction.rollback()
54             error_msg = u"Error at sled run '{0}': {1}".format(sledrun_page.page_title, unicode(e))
55             raise UpdateCacheError(error_msg, sledrun_page.page_title, e)
56     transaction.commit()
57
58
59 def update_wrinncache(connection):
60     """Updates the wrinncache table from the wiki. If convert errors occur, an UpdateCacheError exception
61     is raised. No other exception type should be raised under normal circumstances.
62     
63     >>> from sqlalchemy.engine import create_engine
64     >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=0')
65     >>> # see: https://sourceforge.net/tracker/?func=detail&aid=2837134&group_id=22307&atid=374932
66     >>> update_wrinncache(engine.connect())
67     """
68     metadata = schema.MetaData()
69     wrinncache = wrmwdb.wrinncache_table(metadata)
70     page = mwdb.page_table(metadata)
71     categorylinks = mwdb.categorylinks_table(metadata)
72     revision = mwdb.revision_table(metadata)
73     text = mwdb.text_table(metadata)
74
75     transaction = connection.begin()
76
77     # Query all inns
78     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'Gasthaus'))
79     inn_pages = connection.execute(q)
80         
81     # Delete all existing entries in wrinncache
82     # We rely on transactions MySQL InnoDB
83     connection.execute(wrinncache.delete())
84         
85     # Refill wrinncache table
86     for inn_page in inn_pages:
87         try: 
88             start, end, inn = wrmwmarkup.gasthausbox_to_inn(inn_page.old_text)
89             inn.page_id = inn_page.page_id
90             inn.page_title = inn_page.page_title
91             inn.under_construction = connection.execute(select([categorylinks], (categorylinks.c.cl_from==inn_page.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
92             connection.execute(wrinncache.insert(inn.__dict__))
93         except (RuntimeError, formencode.Invalid) as e:
94             transaction.rollback()
95             error_msg = u"Error as inn '{0}': {1}".format(inn_page.page_title, unicode(e))
96             raise UpdateCacheError(error_msg, inn_page.page_title, e)
97     transaction.commit()
98
99
100 def update_wrreportcache(connection, page_id=None):
101     """Updates the wrreportcache table.
102     :param connection: sqlalchemy connection
103     :param page_id: Updates only the reportcache table for the sledrun described on the Winterrodeln wiki page
104         with the specified page_id. Use None for this parameter to update the whole table.
105
106     >>> from sqlalchemy.engine import create_engine
107     >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
108     >>> # see: https://sourceforge.net/tracker/?func=detail&aid=2837134&group_id=22307&atid=374932
109     >>> update_wrreportcache(engine.connect())
110     """
111     metadata = schema.MetaData()
112     wrreport = wrmwdb.wrreport_table(metadata)
113     wrreportcache = wrmwdb.wrreportcache_table(metadata)
114     transaction = connection.begin()
115
116     # Delete the datasets we are going to update
117     sql_del = wrreportcache.delete()
118     if not page_id is None: sql_del = sql_del.where(wrreportcache.c.page_id == page_id)
119     connection.execute(sql_del)
120
121     def insert_row(connection, rowlist):
122         if len(rowlist) == 0: return
123         # Insert the report
124         row = dict(rowlist[0])
125         connection.execute(wrreportcache.insert(values=row))
126
127     # Select the rows to update
128     sql = 'select page_id, page_title, wrreport.id as report_id, date_report, `condition`, description, author_name, if(author_userid is null, null, author_username) as author_username from wrreport where {0}`condition` is not null and date_invalid > now() and delete_date is null order by page_id, date_report desc, date_entry desc'.format('' if page_id is None else 'page_id={0} and '.format(page_id))
129     cursor = connection.execute(sql)
130     page_id = None
131     rowlist = []
132     for row in cursor:
133         if row.page_id != page_id:
134             insert_row(connection, rowlist)
135             page_id = row.page_id
136             rowlist = []
137         rowlist.append(row)
138     insert_row(connection, rowlist)
139     transaction.commit()
140
141
142 def update_wrmapcache(connection):
143     """Updates the wrmappointcache and wrmappathcache tables from the wiki. If convert errors occur, an UpdateCacheError exception
144     is raised. No other exception type should be raised under normal circumstances.
145     
146     >>> from sqlalchemy.engine import create_engine
147     >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=0')
148     >>> # or: engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=0&passwd=XXXXX')
149     >>> # see: https://sourceforge.net/tracker/?func=detail&aid=2837134&group_id=22307&atid=374932
150     >>> connection = engine.connect()
151     >>> update_wrmapcache(connection)
152     """
153     metadata = schema.MetaData()
154     page = mwdb.page_table(metadata)
155     categorylinks = mwdb.categorylinks_table(metadata)
156     revision = mwdb.revision_table(metadata)
157     text = mwdb.text_table(metadata)
158
159     transaction = connection.begin()
160
161     # Query all sledruns
162     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'))
163     sledrun_pages = connection.execute(q)
164     # Original SQL:
165     # 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"
166     
167     # Delete all existing entries in wrmappointcache
168     # We rely on transactions MySQL InnoDB
169     connection.execute('delete from wrmappointcache')
170     connection.execute('delete from wrmappathcache')
171     
172     # Refill wrmappointcache and wrmappathcache tables
173     for sledrun_page in sledrun_pages:
174         try: 
175             result = mwmarkup.parse_googlemap(sledrun_page.old_text)
176             if not result is None:
177                 center, zoom, coords, paths = result
178                 # Points
179                 for coord in coords:
180                     lon, lat, point_type, label = coord
181                     point_types = {u'Gasthaus': u'hut', u'Haltestelle': u'busstop', u'Parkplatz': u'carpark', u'Achtung': u'warning'}
182                     if not point_type is None:
183                         if not point_types.has_key(point_type): raise RuntimeError(u'Unknown point type {0}'.format(point_type))
184                         point_type = point_types[point_type]
185                         sql = u'insert into wrmappointcache (page_id, type, point, label) values (%s, %s, POINT(%s, %s), %s)'
186                         connection.execute(sql, (sledrun_page.page_id, point_type, lon, lat, label))
187                 # Paths
188                 for path_type, coords in paths:
189                     path_type = path_type.lower()
190                     path_types = {u'6#ff014e9a': u'sledrun', u'6#ffe98401': u'walkup', u'6#ff7f7fff': u'alternative', u'3#ff000000': u'lift', u'3#ffe1e100': u'recommendedcarroute'}
191                     if not path_types.has_key(path_type): raise RuntimeError(u'Unknown path type {0}'.format(path_type))
192                     path_type = path_types[path_type]
193                     path = u", ".join(["{0} {1}".format(lon, lat) for lon, lat, symbol, title in coords])
194                     path = u'LineString({0})'.format(path)
195                     if path_type == u'recommendedcarroute': continue
196                     sql = u'insert into wrmappathcache (path, page_id, type) values (GeomFromText(%s), %s, %s)'
197                     connection.execute(sql, (path, sledrun_page.page_id, path_type))
198         except RuntimeError as e:
199             error_msg = u"Error at sledrun '{0}': {1}".format(sledrun_page.page_title, unicode(e))
200             transaction.rollback()
201             raise UpdateCacheError(error_msg, sledrun_page.page_title, e)
202     transaction.commit()