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