Added support for table wrreportcache.
[philipp/winterrodeln/wrpylib.git] / wrpylib / wrmwcache.py
1 #!/usr/bin/python2.6
2 # -*- coding: iso-8859-15 -*-
3 # $Id$
4 # $HeadURL$
5 """Contains functions that maintain/update the cache tables."""
6 from xml.etree import ElementTree
7 from sqlalchemy import schema
8 from sqlalchemy.sql import select
9 import formencode
10 from wrpylib import mwdb, wrmwdb, wrmwmarkup
11
12
13 class UpdateCacheError(RuntimeError):
14     pass
15
16
17 def update_wrsledruncache(connection):
18     """Updates the wrsledruncache table from the wiki. If convert errors occur, an UpdateCacheError exception
19     is raised. No other exception type should be raised under normal circumstances.
20     
21     >>> from sqlalchemy.engine import create_engine
22     >>> engine = create_engine('mysql://philipp@localhost:3306/winterrodeln_wiki?charset=utf8&use_unicode=0')
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/winterrodeln_wiki?charset=utf8&use_unicode=0')
65     >>> update_wrinncache(engine.connect())
66     """
67     metadata = schema.MetaData()
68     wrinncache = wrmwdb.wrinncache_table(metadata)
69     page = mwdb.page_table(metadata)
70     categorylinks = mwdb.categorylinks_table(metadata)
71     revision = mwdb.revision_table(metadata)
72     text = mwdb.text_table(metadata)
73
74     transaction = connection.begin()
75
76     # Query all inns
77     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'))
78     inn_pages = connection.execute(q)
79         
80     # Delete all existing entries in wrinncache
81     # We rely on transactions MySQL InnoDB
82     connection.execute(wrinncache.delete())
83         
84     # Refill wrinncache table
85     for inn_page in inn_pages:
86         try: 
87             start, end, inn = wrmwmarkup.gasthausbox_to_inn(inn_page.old_text)
88             inn.page_id = inn_page.page_id
89             inn.page_title = inn_page.page_title
90             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
91             connection.execute(wrinncache.insert(inn.__dict__))
92         except (RuntimeError, formencode.Invalid) as e:
93             transaction.rollback()
94             error_msg = u"Error as inn '{0}': {1}".format(inn_page.page_title, unicode(e))
95             raise UpdateCacheError(error_msg, inn_page.page_title, e)
96     transaction.commit()
97
98
99 def update_wrreportcache(connection, page_id=None):
100     """Updates the wrreportcache table.
101     :param connection: sqlalchemy connection
102     :param page_id: Updates only the reportcache table for the sledrun described on the Winterrodeln wiki page
103         with the specified page_id. Use None for this parameter to update the whole table.
104
105     >>> from sqlalchemy.engine import create_engine
106     >>> engine = create_engine('mysql://philipp@localhost:3306/winterrodeln_wiki?charset=utf8&use_unicode=1')
107     >>> update_wrreportcache(engine.connect())
108     """
109     metadata = schema.MetaData()
110     wrreport = wrmwdb.wrreport_table(metadata)
111     wrreportcache = wrmwdb.wrreportcache_table(metadata)
112     transaction = connection.begin()
113
114     # Delte the datasets we are going to update
115     sql_del = wrreportcache.delete()
116     if not page_id is None: sql_del = sql_del.where(wrreportcache.c.page_id == page_id)
117     connection.execute(sql_del)
118
119     def insert_row(connection, rowlist):
120         if len(rowlist) == 0: return
121         # Build XML
122         reports_xml = ElementTree.Element('reports')
123         for row in rowlist:
124             report_xml = ElementTree.SubElement(reports_xml, 'report')
125             report_xml.set('report_id', unicode(row.report_id))
126             report_xml.set('date_report', unicode(row.report_date_report))
127             report_xml.set('condition', unicode(row.report_condition))
128             report_xml.set('author_name', unicode(row.report_author_name))
129             report_xml.set('author_username', unicode(row.report_author_username))
130             report_xml.text = unicode(row.report_description)
131         reports_xml.set('page_id', unicode(row.page_id))
132         reports_xml.set('page_title', row.page_title)
133         reports_xml = unicode(ElementTree.tostring(reports_xml, 'utf8'), 'utf8') # there is not ElementTree.tounicode())
134         # Insert the report(s)
135         row = dict(rowlist[0])
136         row['reports_xml'] = reports_xml
137         connection.execute(wrreportcache.insert(values=row))
138
139     # Select the rows to update
140     sql = 'select page_id, page_title, wrreport.id as report_id, date_report as report_date_report, `condition` as report_condition, description as report_description, author_name as report_author_name, if(author_userid is null, null, author_username) as report_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))
141     cursor = connection.execute(sql)
142     page_id = None
143     rowlist = []
144     for row in cursor:
145         if row.page_id != page_id:
146             insert_row(connection, rowlist)
147             page_id = row.page_id
148             rowlist = []
149         rowlist.append(row)
150     insert_row(connection, rowlist)
151     transaction.commit()
152