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