iwla

iwla Git Source Tree

Root/display.py

1# -*- coding: utf-8 -*-
2#
3# Copyright Grégory Soutadé 2015
4
5# This file is part of iwla
6
7# iwla is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# iwla is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with iwla. If not, see <http://www.gnu.org/licenses/>.
19#
20
21import os
22import codecs
23import time
24import logging
25
26#
27# Create output HTML files
28#
29
30# Just for detection
31def _(name): pass
32_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July')
33_('August'), _('September'), _('October'), _('November'), _('December')
34del _
35
36class DisplayHTMLRaw(object):
37
38 def __init__(self, iwla, html=u''):
39 self.iwla = iwla
40 self.html = html
41
42 def setRawHTML(self, html):
43 self.html = html
44
45 def _buildHTML(self):
46 pass
47
48 def _build(self, f, html):
49 if html: f.write(html)
50
51 def build(self, f):
52 self._buildHTML()
53 self._build(f, self.html)
54
55 def getTitle(self):
56 return ''
57
58class DisplayHTMLBlock(DisplayHTMLRaw):
59
60 def __init__(self, iwla, title=''):
61 super(DisplayHTMLBlock, self).__init__(iwla, html='')
62 self.title = title
63 self.cssclass = u'iwla_block'
64 self.title_cssclass = u'iwla_block_title'
65 self.value_cssclass = u'iwla_block_value'
66
67 def getTitle(self):
68 return self.title
69
70 def setTitle(self, value):
71 self.title = unicode(value)
72
73 def setCSSClass(self, cssclass):
74 self.cssclass = unicode(cssclass)
75
76 def setTitleCSSClass(self, cssclass):
77 self.title_cssclass = unicode(cssclass)
78
79 def setValueCSSClass(self, cssclass):
80 self.value_cssclass = unicode(cssclass)
81
82 def _buildHTML(self):
83 html = u'<div class="%s">' % (self.cssclass)
84 if self.title:
85 html += u'<div class="%s">%s</div>' % (self.title_cssclass, self.title)
86 html += u'<div class="%s">%s</div>' % (self.value_cssclass, self.html)
87 html += u'</div>'
88
89 self.html = html
90
91class DisplayHTMLBlockTable(DisplayHTMLBlock):
92
93 def __init__(self, iwla, title, cols):
94 super(DisplayHTMLBlockTable, self).__init__(iwla=iwla, title=title)
95 self.cols = listToStr(cols)
96 self.rows = []
97 self.cols_cssclasses = [u''] * len(cols)
98 self.rows_cssclasses = []
99 self.table_css = u'iwla_table'
100
101 def appendRow(self, row):
102 self.rows.append(listToStr(row))
103 self.rows_cssclasses.append([u''] * len(row))
104
105 def insertCol(self, col_number, col_title='', col_css_class=''):
106 self.cols.insert(col_number, col_title)
107 for r in self.rows:
108 r.insert(col_number, u'')
109 for r in self.rows_cssclasses:
110 v = r[0]
111 # If all cells have the same CSS class, set it
112 for cur_value in r:
113 if v != cur_value:
114 v = None
115 break
116 v = v or u''
117 r.insert(col_number, v)
118 self.cols_cssclasses.insert(col_number, col_css_class)
119
120 def getNbRows(self):
121 return len(self.rows)
122
123 def getNbCols(self):
124 return len(self.cols)
125
126 def getCellValue(self, row, col):
127 if row < 0 or col < 0 or\
128 row >= len(self.rows) or col >= len(self.cols):
129 raise ValueError('Invalid indices %d,%d' % (row, col))
130
131 return self.rows[row][col]
132
133 def setCellValue(self, row, col, value):
134 if row < 0 or col < 0 or\
135 row >= len(self.rows) or col >= len(self.cols):
136 raise ValueError('Invalid indices %d,%d' % (row, col))
137
138 self.rows[row][col] = unicode(value)
139
140 def setCellCSSClass(self, row, col, value):
141 if row < 0 or col < 0 or\
142 row >= len(self.rows) or col >= len(self.cols):
143 raise ValueError('Invalid indices %d,%d' % (row, col))
144
145 self.rows_cssclasses[row][col] = unicode(value)
146
147 def getCellCSSClass(self, row, col):
148 if row < 0 or col < 0 or\
149 row >= len(self.rows) or col >= len(self.cols):
150 raise ValueError('Invalid indices %d,%d' % (row, col))
151
152 return self.rows_cssclasses[row][col]
153
154 def getColCSSClass(self, col):
155 if col < 0 or col >= len(self.cols):
156 raise ValueError('Invalid indice %d' % (col))
157
158 return self.cols_cssclasses[col]
159
160 def setRowCSSClass(self, row, value):
161 if row < 0 or row >= len(self.rows):
162 raise ValueError('Invalid indice %d' % (row))
163
164 self.rows_cssclasses[row] = [unicode(value)] * len(self.rows_cssclasses[row])
165
166 def setColCSSClass(self, col, value):
167 if col < 0 or col >= len(self.cols):
168 raise ValueError('Invalid indice %d' % (col))
169
170 self.cols_cssclasses[col] = unicode(value)
171
172 def setColsCSSClass(self, values):
173 if len(values) != len(self.cols):
174 raise ValueError('Invalid values size')
175
176 self.cols_cssclasses = listToStr(values)
177
178 def computeRatio(self, column, column_insertion=None):
179 if column_insertion is None:
180 column_insertion = column+1
181
182 total = 0
183 for r in self.rows:
184 if r[column]:
185 total += int(r[column])
186
187 self.insertCol(column_insertion, self.iwla._('Ratio'), u'iwla_hit')
188 for (index, r) in enumerate(self.rows):
189 val = r[column] and int(r[column]) or 0
190 self.setCellValue(index, column_insertion, '%.1f%%' % (float(val*100)/float(total)))
191
192 def _buildHTML(self):
193 style = u''
194 if self.table_css: style = u' class="%s"' % (self.table_css)
195 html = u'<table%s>' % (style)
196 if self.cols:
197 html += u'<tr>'
198 for i in range (0, len(self.cols)):
199 title = self.cols[i]
200 style = self.getColCSSClass(i)
201 if style: style = u' class="%s"' % (style)
202 html += u'<th%s>%s</th>' % (style, title)
203 html += u'</tr>'
204 for i in range(0, len(self.rows)):
205 row = self.rows[i]
206 html += u'<tr>'
207 for j in range(0, len(row)):
208 v = row[j]
209 style = self.getCellCSSClass(i, j)
210 if style: style = u' class="%s"' % (style)
211 html += u'<td%s>%s</td>' % (style, v)
212 html += u'</tr>'
213 html += u'</table>'
214
215 self.html += html
216
217 super(DisplayHTMLBlockTable, self)._buildHTML()
218
219class DisplayHTMLBlockTableWithGraph(DisplayHTMLBlockTable):
220
221 def __init__(self, iwla, title, cols, short_titles=None, nb_valid_rows=0, graph_cols=None):
222 super(DisplayHTMLBlockTableWithGraph, self).__init__(iwla=iwla, title=title, cols=cols)
223 self.short_titles = short_titles or []
224 self.short_titles = listToStr(self.short_titles)
225 self.nb_valid_rows = nb_valid_rows
226 self.icon_path = self.iwla.getConfValue('icon_path', '/')
227 self.raw_rows = []
228 self.maxes = [0] * len(cols)
229 self.table_graph_css = u'iwla_graph_table'
230 self.td_img_css = u'iwla_td_img'
231 self.graph_cols = graph_cols or []
232
233 def appendRow(self, row):
234 self.raw_rows.append(row)
235 super(DisplayHTMLBlockTableWithGraph, self).appendRow(row)
236
237 def appendShortTitle(self, short_title):
238 self.short_titles.append(unicode(short_title))
239
240 def setShortTitle(self, short_titles):
241 self.short_titles = listToStr(short_titles)
242
243 def setNbValidRows(self, nb_valid_rows):
244 self.nb_valid_rows = nb_valid_rows
245
246 def _computeMax(self):
247 for i in range(0, self.nb_valid_rows):
248 row = self.raw_rows[i]
249 for j in range(1, len(row)):
250 if row[j] > self.maxes[j]:
251 self.maxes[j] = row[j]
252
253 def _getIconFromStyle(self, style):
254 if style.startswith(u'iwla_page'): icon = u'vp.png'
255 elif style.startswith(u'iwla_hit'): icon = u'vh.png'
256 elif style.startswith(u'iwla_bandwidth'): icon = u'vk.png'
257 elif style.startswith(u'iwla_visitor'): icon = u'vu.png'
258 elif style.startswith(u'iwla_visit'): icon = u'vv.png'
259 else: return ''
260
261 return u'/%s/other/%s' % (self.icon_path, icon)
262
263 def _buildHTML(self):
264 self._computeMax()
265
266 style = u''
267 if self.table_graph_css: style = u' class="%s"' % (self.table_graph_css)
268 html = u'<table%s>' % (style)
269 html += u'<tr>'
270 for i in range(0, self.nb_valid_rows):
271 row = self.rows[i]
272 css = u''
273 if self.td_img_css: css=u' class="%s"' % (self.td_img_css)
274 html += u'<td%s>' % (css)
275 for j in self.graph_cols:
276 style = self.getColCSSClass(j)
277 icon = self._getIconFromStyle(style)
278 if not icon: continue
279 if style: style = u' class="%s"' % (style)
280 alt = u'%s: %s' % (row[j], self.cols[j])
281 if self.maxes[j]:
282 height = int((self.raw_rows[i][j] * 100) / self.maxes[j]) or 1
283 else:
284 height = 1
285 html += u'<img%s src="%s" height="%d" width="6" alt="%s" title="%s" />' % (style, icon, height, alt, alt)
286 html += u'</td>'
287 html += u'</tr>'
288 html += u'<tr>'
289 for i in range(0, len(self.short_titles)):
290 style = self.getCellCSSClass(i, 0)
291 if style: style = u' class="%s"' % (style)
292 html += u'<td%s>%s</td>' % (style, self.short_titles[i])
293 html += u'</tr>'
294 html += u'</table>'
295
296 self.html += html
297
298 super(DisplayHTMLBlockTableWithGraph, self)._buildHTML()
299
300class DisplayHTMLPage(object):
301
302 def __init__(self, iwla, title, filename, css_path):
303 self.iwla = iwla
304 self.title = unicode(title)
305 self.filename = filename
306 self.blocks = []
307 self.css_path = listToStr(css_path)
308 self.logger = logging.getLogger(self.__class__.__name__)
309
310 def getFilename(self):
311 return self.filename;
312
313 def getBlock(self, title):
314 for b in self.blocks:
315 if title == b.getTitle():
316 return b
317 return None
318
319 def appendBlock(self, block):
320 self.blocks.append(block)
321
322 def build(self, root, displayVersion=True):
323 filename = os.path.join(root, self.filename)
324
325 base = os.path.dirname(filename)
326 if not os.path.exists(base):
327 os.makedirs(base)
328
329 self.logger.debug('Write %s' % (filename))
330
331 f = codecs.open(filename, 'w', 'utf-8')
332 f.write(u'<!DOCTYPE html>')
333 f.write(u'<html>')
334 f.write(u'<head>')
335 f.write(u'<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />')
336 for css in self.css_path:
337 f.write(u'<link rel="stylesheet" href="/%s"/>' % (css))
338 if self.title:
339 f.write(u'<title>%s</title>' % (self.title))
340 f.write(u'</head><body>')
341 for block in self.blocks:
342 block.build(f)
343 if displayVersion:
344 f.write(u'<center>Generated by <a href="%s">IWLA %s</a></center>' %
345 ("http://indefero.soutade.fr/p/iwla", self.iwla.getVersion()))
346 f.write(u'</body></html>')
347 f.close()
348
349class DisplayHTMLBuild(object):
350
351 def __init__(self, iwla):
352 self.pages = []
353 self.iwla = iwla
354
355 def createPage(self, *args):
356 return DisplayHTMLPage(self.iwla, *args)
357
358 def createBlock(self, _class, *args):
359 return _class(self.iwla, *args)
360
361 def getPage(self, filename):
362 for page in self.pages:
363 if page.getFilename() == filename:
364 return page
365 return None
366
367 def addPage(self, page):
368 self.pages.append(page)
369
370 def build(self, root):
371 display_root = self.iwla.getConfValue('DISPLAY_ROOT', '')
372 if not os.path.exists(display_root):
373 os.makedirs(display_root)
374 for res_path in self.iwla.getResourcesPath():
375 target = os.path.abspath(res_path)
376 link_name = os.path.join(display_root, res_path)
377 if not os.path.exists(link_name):
378 os.symlink(target, link_name)
379
380 for page in self.pages:
381 page.build(root)
382
383#
384# Global functions
385#
386
387def bytesToStr(bytes):
388 suffixes = [u'', u' kB', u' MB', u' GB', u' TB']
389
390 for i in range(0, len(suffixes)):
391 if bytes < 1024: break
392 bytes /= 1024.0
393
394 if i:
395 return u'%.02f%s' % (bytes, suffixes[i])
396 else:
397 return u'%d%s' % (bytes, suffixes[i])
398
399def _toStr(v):
400 if type(v) != unicode: return unicode(v)
401 else: return v
402
403def listToStr(l): return map(lambda(v) : _toStr(v), l)
404
405def generateHTMLLink(url, name=None, max_length=100, prefix=u'http'):
406 url = unicode(url)
407 if not name: name = unicode(url)
408 if not url.startswith(prefix): url = u'%s://%s' % (prefix, url)
409 return u'<a href="%s">%s</a>' % (url, name[:max_length])
410
411def createCurTitle(iwla, title):
412 title = iwla._(title)
413 month_name = time.strftime(u'%B', iwla.getCurTime())
414 year = time.strftime(u'%Y', iwla.getCurTime())
415 title += u' - %s %s' % (iwla._(month_name), year)
416 domain_name = iwla.getConfValue('domain_name', '')
417 if domain_name:
418 title += u' - %s' % (domain_name)
419 return title
420

Archive Download this file

Branches

Tags