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