2 # -*- coding: iso-8859-15 -*-
5 """Contains functions that maintain/update the cache tables."""
6 from sqlalchemy import schema
7 from sqlalchemy.sql import select
8 from sqlalchemy.sql.expression import func as sqlfunc
11 from wrpylib import mwdb, wrmwdb, mwmarkup, wrmwmarkup, wrvalidators
14 class UpdateCacheError(RuntimeError):
18 def update_wrsledruncache(connection):
19 """Updates the wrsledruncache table from the wiki. If convert errors occur, an UpdateCacheError exception
20 is raised. No other exception type should be raised under normal circumstances.
22 >>> from sqlalchemy.engine import create_engine
23 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
24 >>> update_wrsledruncache(engine.connect())
26 metadata = schema.MetaData()
27 wrsledruncache = wrmwdb.wrsledruncache_table(metadata)
28 page = mwdb.page_table(metadata)
29 categorylinks = mwdb.categorylinks_table(metadata)
30 revision = mwdb.revision_table(metadata)
31 text = mwdb.text_table(metadata)
33 transaction = connection.begin()
36 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=='Rodelbahn'))
37 sledrun_pages = connection.execute(q)
39 # 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"
41 # Delete all existing entries in wrsledruncache
42 # We rely on transactions MySQL InnoDB
43 connection.execute(wrsledruncache.delete())
45 # Refill wrsledruncache table
46 for sledrun_page in sledrun_pages:
48 start, end, sledrun = wrmwmarkup.rodelbahnbox_to_sledrun(sledrun_page.old_text)
49 sledrun.page_id = sledrun_page.page_id
50 sledrun.page_title = sledrun_page.page_title
51 sledrun.name_url = wrvalidators.sledrun_page_title_to_pretty_url(sledrun_page.page_title)
52 sledrun.under_construction = connection.execute(select([categorylinks], (categorylinks.c.cl_from==sledrun_page.page_id) & (categorylinks.c.cl_to == 'In_Arbeit')).alias('x').count()).fetchone()[0] > 0 # It would be better to do this in the query above
53 connection.execute(wrsledruncache.insert(sledrun.__dict__))
54 except (RuntimeError, formencode.Invalid) as e:
55 transaction.rollback()
56 error_msg = "Error at sled run '{0}': {1}".format(sledrun_page.page_title, str(e))
57 raise UpdateCacheError(error_msg, sledrun_page.page_title, e)
61 def update_wrinncache(connection):
62 """Updates the wrinncache table from the wiki. If convert errors occur, an UpdateCacheError exception
63 is raised. No other exception type should be raised under normal circumstances.
65 >>> from sqlalchemy.engine import create_engine
66 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
67 >>> update_wrinncache(engine.connect())
69 metadata = schema.MetaData()
70 wrinncache = wrmwdb.wrinncache_table(metadata)
71 page = mwdb.page_table(metadata)
72 categorylinks = mwdb.categorylinks_table(metadata)
73 revision = mwdb.revision_table(metadata)
74 text = mwdb.text_table(metadata)
76 transaction = connection.begin()
79 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=='Gasthaus'))
80 inn_pages = connection.execute(q)
82 # Delete all existing entries in wrinncache
83 # We rely on transactions MySQL InnoDB
84 connection.execute(wrinncache.delete())
86 # Refill wrinncache table
87 for inn_page in inn_pages:
89 start, end, inn = wrmwmarkup.gasthausbox_to_inn(inn_page.old_text)
90 inn.page_id = inn_page.page_id
91 inn.page_title = inn_page.page_title
92 inn.under_construction = connection.execute(select([categorylinks], (categorylinks.c.cl_from==inn_page.page_id) & (categorylinks.c.cl_to == 'In_Arbeit')).alias('x').count()).fetchone()[0] > 0 # It would be better to do this in the query above
93 connection.execute(wrinncache.insert(inn.__dict__))
94 except (RuntimeError, formencode.Invalid) as e:
95 transaction.rollback()
96 error_msg = "Error as inn '{0}': {1}".format(inn_page.page_title, str(e))
97 raise UpdateCacheError(error_msg, inn_page.page_title, e)
101 def update_wrreportcache(connection, page_id=None):
102 """Updates the wrreportcache table.
103 :param connection: sqlalchemy connection
104 :param page_id: Updates only the reportcache table for the sledrun described on the Winterrodeln wiki page
105 with the specified page_id. Use None for this parameter to update the whole table.
107 >>> from sqlalchemy.engine import create_engine
108 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
109 >>> update_wrreportcache(engine.connect())
111 metadata = schema.MetaData()
112 wrreport = wrmwdb.wrreport_table(metadata)
113 wrreportcache = wrmwdb.wrreportcache_table(metadata)
114 transaction = connection.begin()
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)
121 def insert_row(connection, rowlist):
122 if len(rowlist) == 0: return
124 row = dict(rowlist[0])
125 connection.execute(wrreportcache.insert(values=row))
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)
133 if row.page_id != page_id:
134 insert_row(connection, rowlist)
135 page_id = row.page_id
138 insert_row(connection, rowlist)
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.
146 >>> from sqlalchemy.engine import create_engine
147 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
148 >>> # or: engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1&passwd=XXXXX')
149 >>> update_wrmapcache(engine.connect())
151 metadata = schema.MetaData()
152 page = mwdb.page_table(metadata)
153 categorylinks = mwdb.categorylinks_table(metadata)
154 revision = mwdb.revision_table(metadata)
155 text = mwdb.text_table(metadata)
157 transaction = connection.begin()
160 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=='Rodelbahn'))
161 sledrun_pages = connection.execute(q)
163 # 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"
165 # Delete all existing entries in wrmappointcache
166 # We rely on transactions MySQL InnoDB
167 connection.execute('delete from wrmappointcache')
168 connection.execute('delete from wrmappathcache')
170 # Refill wrmappointcache and wrmappathcache tables
171 for sledrun_page in sledrun_pages:
173 start, content, endtag, end = mwmarkup.find_tag(sledrun_page.old_text, 'wrmap')
176 geojson = wrmwmarkup.parse_wrmap(sledrun_page.old_text[start:end])
178 for feature in geojson['features']:
179 properties = feature['properties']
180 coordinates = feature['geometry']['coordinates']
183 if properties['type'] in wrmwmarkup.WRMAP_POINT_TYPES:
184 lon, lat = coordinates
185 label = properties.get('name')
186 point_types = {'gasthaus': 'hut', 'haltestelle': 'busstop', 'parkplatz': 'carpark', 'achtung': 'warning', 'foto': 'photo', 'verleih': 'rental', 'punkt': 'point'}
187 point_type = point_types[properties['type']]
188 sql = 'insert into wrmappointcache (page_id, type, point, label) values (%s, %s, POINT(%s, %s), %s)'
189 connection.execute(sql, (sledrun_page.page_id, point_type, lon, lat, label))
192 elif properties['type'] in wrmwmarkup.WRMAP_LINE_TYPES:
193 path_types = {'rodelbahn': 'sledrun', 'gehweg': 'walkup', 'alternative': 'alternative', 'lift': 'lift', 'anfahrt': 'recommendedcarroute', 'linie': 'line'}
194 path_type = path_types[properties['type']]
195 path = ", ".join(["{0} {1}".format(lon, lat) for lon, lat in coordinates])
196 path = 'LineString({0})'.format(path)
197 if path_type == 'recommendedcarroute': continue
198 sql = 'insert into wrmappathcache (path, page_id, type) values (GeomFromText(%s), %s, %s)'
199 connection.execute(sql, (path, sledrun_page.page_id, path_type))
202 raise RuntimeError('Unknown feature type {0}'.format(properties['type']))
203 except RuntimeError as e:
204 error_msg = "Error at sledrun '{0}': {1}".format(sledrun_page.page_title, str(e))
205 transaction.rollback()
206 raise UpdateCacheError(error_msg, sledrun_page.page_title, e)
210 def update_wrregioncache(connection):
211 """Updates the wrregioncache table from the wiki.
212 It relays on the table wrsledruncache to be up-to-date.
213 No exceptions should be raised under normal circumstances.
215 >>> from sqlalchemy.engine import create_engine
216 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
217 >>> # or: engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1&passwd=XXXXX')
218 >>> update_wrregioncache(engine.connect())
220 metadata = schema.MetaData()
221 wrregion = wrmwdb.wrregion_table(metadata)
222 wrsledruncache = wrmwdb.wrsledruncache_table(metadata)
223 wrregioncache = wrmwdb.wrregioncache_table(metadata)
225 transaction = connection.begin()
227 # Delete all existing entries in wrregioncache
228 # We rely on transactions MySQL InnoDB
229 connection.execute(wrregioncache.delete())
231 # Query all combinations of sledruns and regions
232 sel = select([wrregion.c.id.label('region_id'), sqlfunc.AsWKB(wrregion.c.border).label('border'), wrsledruncache.c.page_id, wrsledruncache.c.position_longitude, wrsledruncache.c.position_latitude], sqlfunc.contains(wrregion.c.border, sqlfunc.point(wrsledruncache.c.position_longitude, wrsledruncache.c.position_latitude)))
233 ins = wrregioncache.insert()
235 # Refill wrregioncache
236 point = ogr.Geometry(ogr.wkbPoint)
237 result = connection.execute(sel)
239 point.SetPoint(0, row.position_longitude, row.position_latitude)
240 if point.Within(ogr.CreateGeometryFromWkb(row.border)):
241 connection.execute(ins.values(region_id=row.region_id, page_id=row.page_id))