]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - webapp/ui_modules.py
Fix tracker.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 from tornado.database import Row
17
18 import backend
19 import backend.stasy
20
21 class UIModule(tornado.web.UIModule):
22 @property
23 def accounts(self):
24 return self.handler.accounts
25
26 @property
27 def advertisements(self):
28 return self.handler.advertisements
29
30 @property
31 def banners(self):
32 return self.handler.banners
33
34 @property
35 def memcached(self):
36 return self.handler.memcached
37
38 @property
39 def releases(self):
40 return self.handler.releases
41
42 @property
43 def geoip(self):
44 return self.handler.geoip
45
46 @property
47 def news(self):
48 return self.handler.news
49
50 @property
51 def planet(self):
52 return self.handler.planet
53
54 @property
55 def wishlist(self):
56 return self.handler.wishlist
57
58
59 class 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
73 class MapModule(UIModule):
74 def render(self, latitude, longitude):
75 return self.render_string("modules/map.html", latitude=latitude, longitude=longitude)
76
77
78 class MenuModule(UIModule):
79 def render(self):
80 return self.render_string("modules/menu.html")
81
82
83 class MirrorItemModule(UIModule):
84 def render(self, item):
85 return self.render_string("modules/mirror-item.html", item=item)
86
87
88 class 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
94 class NetBootMenuConfigModule(UIModule):
95 def render(self, release):
96 return self.render_string("netboot/menu-config.cfg", release=release)
97
98
99 class 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
109 class NetBootMenuSeparatorModule(UIModule):
110 def render(self):
111 return self.render_string("netboot/menu-separator.cfg")
112
113
114 class NewsItemModule(UIModule):
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
124 def render(self, item, uncut=True, announcement=False, show_heading=True):
125 # Get author
126 item.author = self.get_author(item.author_id)
127
128 if not uncut and len(item.text) >= 400:
129 item.text = item.text[:400] + "..."
130
131 # Render text
132 item.text = textile.textile(item.text)
133
134 return self.render_string("modules/news-item.html", item=item,
135 uncut=uncut, announcement=announcement, show_heading=show_heading)
136
137
138 class NewsLineModule(UIModule):
139 def render(self, item):
140 return self.render_string("modules/news-line.html", item=item)
141
142
143 class NewsTableModule(UIModule):
144 def render(self, news):
145 return self.render_string("modules/news-table.html", news=news)
146
147
148 class 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
159 class 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
167 class SidebarItemModule(UIModule):
168 def render(self):
169 return self.render_string("modules/sidebar-item.html")
170
171
172 class SidebarReleaseModule(UIModule):
173 def render(self):
174 return self.render_string("modules/sidebar-release.html",
175 latest=self.releases.get_latest())
176
177
178 class ReleaseItemModule(UIModule):
179 def render(self, release, latest=False):
180 arches = ("i586", "arm")
181
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))
194
195 return self.render_string("modules/release-item.html",
196 release=release, latest=latest, downloads=downloads)
197
198
199 class SidebarBannerModule(UIModule):
200 def render(self, item=None):
201 if not item:
202 item = self.banners.get_random()
203
204 return self.render_string("modules/sidebar-banner.html", item=item)
205
206
207 class 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
224 class PlanetEntryModule(UIModule):
225 def render(self, entry, show_avatar=True):
226 return self.render_string("modules/planet-entry.html",
227 entry=entry, show_avatar=show_avatar)
228
229
230 class TrackerPeerListModule(UIModule):
231 def render(self, peers):
232 # Guess country code and hostname of the host
233 for peer in peers:
234 country_code = self.geoip.get_country(peer["ip"])
235 if country_code:
236 country_code = country_code.lower()
237 peer["country_code"] = country_code or "unknown"
238
239 try:
240 peer["hostname"] = socket.gethostbyaddr(peer["ip"])[0]
241 except:
242 peer["hostname"] = ""
243
244 return self.render_string("modules/tracker-peerlist.html",
245 peers=[Row(p) for p in peers])
246
247
248 class StasyTableModule(UIModule):
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
258 def render(self, items, sortby="key", reverse=False, percentage=False, flags=False, locale=False):
259 hundred_percent = 0
260 for v in items.values():
261 hundred_percent += v
262
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
273 if hundred_percent:
274 _items = []
275 for k in keys:
276 if not percentage:
277 v = items[k] * 100 / hundred_percent
278 else:
279 v = items[k] * 100
280 _items.append((k, v))
281 items = _items
282
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
291 if locale:
292 flags = False
293 locales = tornado.locale.LOCALE_NAMES
294 _items = []
295 for k, v in items:
296 if k:
297 for code, locale in locales.items():
298 if code.startswith(k):
299 k = locale["name"].split()[0]
300 _items.append((k, v))
301 items = _items
302
303 return self.render_string("modules/stasy-table.html", items=items, flags=flags)
304
305
306 class 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
318 class 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())
330
331
332 class 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)
349
350
351 class 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
357 class WishModule(UIModule):
358 def render(self, wish, short=False):
359 progress_bar = "progress-bar-warning"
360
361 if wish.percentage >= 100:
362 progress_bar = "progress-bar-success"
363
364 return self.render_string("wishlist/modules/wish.html",
365 wish=wish, short=short, progress_bar=progress_bar)
366
367
368 class WishlistItemsModule(UIModule):
369 def render(self, wishlist_items):
370 return self.render_string("modules/wishlist-items.html",
371 wishlist_items=wishlist_items)
372
373
374 class DonationBoxModule(UIModule):
375 def render(self, reason_for_transfer=None, show_wishlist_items=False):
376 if reason_for_transfer:
377 reason_for_transfer = "IPFire.org - %s" % reason_for_transfer
378
379 # Interesting items from the wishlist.
380 wishlist_items = []
381 if show_wishlist_items:
382 wishlist_items = self.wishlist.get_hot_wishes()
383
384 return self.render_string("modules/donation-box.html",
385 reason_for_transfer=reason_for_transfer, wishlist_items=wishlist_items)