]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blame - webapp/ui_modules.py
boot: Support serial console installations.
[people/shoehn/ipfire.org.git] / webapp / ui_modules.py
CommitLineData
81675874 1#!/usr/bin/python
2
91a446f0
MT
3from __future__ import division
4
de683d7c 5import hashlib
940227cb 6import logging
91a446f0 7import operator
9068dba1 8import re
940227cb
MT
9import socket
10import textile
11import tornado.escape
6af40477 12import tornado.locale
feb02477 13import tornado.web
9068dba1 14import unicodedata
81675874 15
feb02477 16from tornado.database import Row
2c055a8e 17
940227cb 18import backend
91a446f0 19import backend.stasy
940227cb 20
81675874 21class UIModule(tornado.web.UIModule):
940227cb
MT
22 @property
23 def accounts(self):
24 return self.handler.accounts
81675874 25
a0048e66
MT
26 @property
27 def advertisements(self):
28 return self.handler.advertisements
29
d0d074e0 30 @property
940227cb
MT
31 def banners(self):
32 return self.handler.banners
d0d074e0 33
de683d7c
MT
34 @property
35 def memcached(self):
36 return self.handler.memcached
37
940227cb
MT
38 @property
39 def releases(self):
40 return self.handler.releases
81675874 41
638e9782
MT
42 @property
43 def geoip(self):
44 return self.handler.geoip
45
7771acea
MT
46 @property
47 def news(self):
48 return self.handler.news
49
fa7e1a0a
MT
50 @property
51 def planet(self):
52 return self.handler.planet
53
e64ce07e
MT
54 @property
55 def wishlist(self):
56 return self.handler.wishlist
57
5a1018ab 58
a0048e66
MT
59class AdvertisementModule(UIModule):
60 def render(self, where):
61 assert where in ("download-splash",), where
62
63 ad = self.advertisements.get(where)
64 if not ad:
65 return ""
66
67 # Mark that advert has been shown.
68 ad.update_impressions()
69
70 return self.render_string("modules/ads/%s.html" % where, ad=ad)
71
72
9068dba1
MT
73class MapModule(UIModule):
74 def render(self, latitude, longitude):
75 return self.render_string("modules/map.html", latitude=latitude, longitude=longitude)
76
77
940227cb
MT
78class MenuModule(UIModule):
79 def render(self):
60024cc8 80 return self.render_string("modules/menu.html")
81675874 81
82
9068dba1
MT
83class MirrorItemModule(UIModule):
84 def render(self, item):
85 return self.render_string("modules/mirror-item.html", item=item)
86
87
88class MirrorsTableModule(UIModule):
89 def render(self, mirrors, preferred_mirrors=[]):
90 return self.render_string("modules/mirrors-table.html",
91 mirrors=mirrors, preferred_mirrors=preferred_mirrors)
92
93
94class NetBootMenuConfigModule(UIModule):
95 def render(self, release):
96 return self.render_string("netboot/menu-config.cfg", release=release)
97
98
99class NetBootMenuHeaderModule(UIModule):
100 def render(self, title, releases):
101 id = unicodedata.normalize("NFKD", unicode(title)).encode("ascii", "ignore")
102 id = re.sub(r"[^\w]+", " ", id)
103 id = "-".join(id.lower().strip().split())
104
105 return self.render_string("netboot/menu-header.cfg", id=id,
106 title=title, releases=releases)
107
108
109class NetBootMenuSeparatorModule(UIModule):
110 def render(self):
111 return self.render_string("netboot/menu-separator.cfg")
112
113
81675874 114class NewsItemModule(UIModule):
940227cb
MT
115 def get_author(self, author):
116 # Get name of author
117 author = self.accounts.find(author)
118 if author:
119 return author.cn
120 else:
121 _ = self.locale.translate
122 return _("Unknown author")
123
60024cc8 124 def render(self, item, uncut=True, announcement=False, show_heading=True):
940227cb
MT
125 # Get author
126 item.author = self.get_author(item.author_id)
81675874 127
940227cb
MT
128 if not uncut and len(item.text) >= 400:
129 item.text = item.text[:400] + "..."
81675874 130
940227cb 131 # Render text
9068dba1 132 item.text = textile.textile(item.text)
81675874 133
60024cc8
MT
134 return self.render_string("modules/news-item.html", item=item,
135 uncut=uncut, announcement=announcement, show_heading=show_heading)
940227cb
MT
136
137
7771acea 138class NewsLineModule(UIModule):
940227cb
MT
139 def render(self, item):
140 return self.render_string("modules/news-line.html", item=item)
141
142
7771acea
MT
143class NewsTableModule(UIModule):
144 def render(self, news):
145 return self.render_string("modules/news-table.html", news=news)
146
147
148class NewsYearNavigationModule(UIModule):
149 def render(self, active=None):
150 try:
151 active = int(active)
152 except:
153 active = None
154
155 return self.render_string("modules/news-year-nav.html",
156 active=active, years=self.news.years)
157
158
fa7e1a0a
MT
159class PlanetSearchBoxModule(UIModule):
160 def render(self, query=None):
161 years = self.planet.get_years()
162
163 return self.render_string("modules/planet/search-box.html",
164 query=query, years=years)
165
166
81675874 167class SidebarItemModule(UIModule):
168 def render(self):
169 return self.render_string("modules/sidebar-item.html")
170
171
172class SidebarReleaseModule(UIModule):
81675874 173 def render(self):
174 return self.render_string("modules/sidebar-release.html",
940227cb 175 latest=self.releases.get_latest())
81675874 176
177
178class ReleaseItemModule(UIModule):
60024cc8 179 def render(self, release, latest=False):
110e8687 180 arches = ("i586", "arm")
60024cc8 181
110e8687
MT
182 downloads = []
183 for arch in ("i586", "arm"):
184 files = []
185
186 for file in release.files:
187 if not file.arch == arch:
188 continue
189
190 files.append(file)
191
192 if files:
193 downloads.append((arch, files))
60024cc8
MT
194
195 return self.render_string("modules/release-item.html",
110e8687 196 release=release, latest=latest, downloads=downloads)
81675874 197
198
199class SidebarBannerModule(UIModule):
940227cb
MT
200 def render(self, item=None):
201 if not item:
202 item = self.banners.get_random()
203
81675874 204 return self.render_string("modules/sidebar-banner.html", item=item)
205
206
60024cc8
MT
207class DownloadButtonModule(UIModule):
208 def render(self, release, text="Download now!"):
209 best_image = None
210
211 for file in release.files:
212 if file.type == "iso":
213 best_image = file
214 break
215
216 # Show nothing when there was no image found.
217 if not best_image:
218 return ""
219
220 return self.render_string("modules/download-button.html",
221 release=release, image=best_image)
222
223
940227cb 224class PlanetEntryModule(UIModule):
60024cc8 225 def render(self, entry, show_avatar=True):
940227cb 226 return self.render_string("modules/planet-entry.html",
60024cc8 227 entry=entry, show_avatar=show_avatar)
d0d074e0
MT
228
229
940227cb 230class TrackerPeerListModule(UIModule):
6d524cba 231 def render(self, peers):
940227cb
MT
232 # Guess country code and hostname of the host
233 for peer in peers:
6d524cba
MT
234 country_code = self.geoip.get_country(peer["ip"])
235 if country_code:
236 country_code = country_code.lower()
940227cb 237 peer["country_code"] = country_code or "unknown"
d0d074e0 238
940227cb
MT
239 try:
240 peer["hostname"] = socket.gethostbyaddr(peer["ip"])[0]
241 except:
242 peer["hostname"] = ""
d0d074e0 243
940227cb 244 return self.render_string("modules/tracker-peerlist.html",
6d524cba 245 peers=[Row(p) for p in peers])
372efc19
MT
246
247
248class StasyTableModule(UIModule):
62c3fa48
MT
249 def _make_percentages(self, items):
250 total = sum(items.values())
251
252 for k in items.keys():
253 items[k] *= 100
254 items[k] /= total
255
256 return items
257
6af40477 258 def render(self, items, sortby="key", reverse=False, percentage=False, flags=False, locale=False):
372efc19
MT
259 hundred_percent = 0
260 for v in items.values():
261 hundred_percent += v
262
91a446f0
MT
263 keys = []
264 if sortby == "key":
265 keys = sorted(items.keys(), reverse=reverse)
266 elif sortby == "percentage":
267 keys = [k for k,v in sorted(items.items(), key=operator.itemgetter(1))]
268 if not reverse:
269 keys = reversed(keys)
270 else:
271 raise Exception, "Unknown sortby parameter was provided"
272
372efc19
MT
273 if hundred_percent:
274 _items = []
91a446f0 275 for k in keys:
e6cff1b1
MT
276 if not percentage:
277 v = items[k] * 100 / hundred_percent
278 else:
279 v = items[k] * 100
372efc19
MT
280 _items.append((k, v))
281 items = _items
282
0d01fda0
MT
283 if items and type(items[0][0]) == type(()) :
284 _ = self.locale.translate
285 _items = []
286 for k, v in items:
287 k = _("%s to %s") % k
288 _items.append((k, v))
289 items = _items
290
6af40477
MT
291 if locale:
292 flags = False
293 locales = tornado.locale.LOCALE_NAMES
294 _items = []
295 for k, v in items:
02888488
MT
296 if k:
297 for code, locale in locales.items():
298 if code.startswith(k):
299 k = locale["name"].split()[0]
6af40477
MT
300 _items.append((k, v))
301 items = _items
302
665ef07e 303 return self.render_string("modules/stasy-table.html", items=items, flags=flags)
91a446f0
MT
304
305
62c3fa48
MT
306class StasyCPUCoreTableModule(StasyTableModule):
307 def render(self, items):
308 items = self._make_percentages(items)
309
310 items = items.items()
311 items.sort()
312
313 return self.render_string("modules/stasy-table.html", items=items,
314 flags=None #XXX
315 )
316
317
91a446f0
MT
318class StasyDeviceTableModule(UIModule):
319 def render(self, devices):
320 groups = {}
321
322 for device in devices:
323 if not groups.has_key(device.cls):
324 groups[device.cls] = []
325
326 groups[device.cls].append(device)
327
328 return self.render_string("modules/stasy-table-devices.html",
329 groups=groups.items())
638e9782
MT
330
331
332class StasyGeoTableModule(UIModule):
333 def render(self, items):
334 _ = self.locale.translate
335
336 # Sort all items by value
337 items = sorted(items.items(), key=operator.itemgetter(1), reverse=True)
338
339 countries = []
340 for code, value in items:
341 country = tornado.database.Row({
342 "code" : code.lower(),
343 "name" : _(self.geoip.get_country_name(code)),
344 "value" : value * 100,
345 })
346 countries.append(country)
347
348 return self.render_string("modules/stasy-table-geo.html", countries=countries)
0673d1b0
MT
349
350
7771acea
MT
351class WishlistModule(UIModule):
352 def render(self, wishes, short=False):
353 return self.render_string("wishlist/modules/wishlist.html",
354 wishes=wishes, short=short)
355
356
357class WishModule(UIModule):
358 def render(self, wish, short=False):
3907b320 359 progress_bar = "progress-bar-warning"
7771acea 360
f60b79ce 361 if wish.percentage >= 100:
3907b320 362 progress_bar = "progress-bar-success"
7771acea
MT
363
364 return self.render_string("wishlist/modules/wish.html",
365 wish=wish, short=short, progress_bar=progress_bar)
366
367
e64ce07e
MT
368class WishlistItemsModule(UIModule):
369 def render(self, wishlist_items):
370 return self.render_string("modules/wishlist-items.html",
371 wishlist_items=wishlist_items)
372
373
7771acea 374class DonationBoxModule(UIModule):
e64ce07e 375 def render(self, reason_for_transfer=None, show_wishlist_items=False):
353880e5
MT
376 if reason_for_transfer:
377 reason_for_transfer = "IPFire.org - %s" % reason_for_transfer
378
e64ce07e
MT
379 # Interesting items from the wishlist.
380 wishlist_items = []
381 if show_wishlist_items:
382 wishlist_items = self.wishlist.get_hot_wishes()
383
353880e5 384 return self.render_string("modules/donation-box.html",
e64ce07e 385 reason_for_transfer=reason_for_transfer, wishlist_items=wishlist_items)