]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - webapp/ui_modules.py
Add wishes to the donation page.
[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, percentages=False):
232 # Guess country code and hostname of the host
233 for peer in peers:
234 country_code = backend.GeoIP().get_country(peer["ip"])
235 peer["country_code"] = country_code or "unknown"
236
237 try:
238 peer["hostname"] = socket.gethostbyaddr(peer["ip"])[0]
239 except:
240 peer["hostname"] = ""
241
242 return self.render_string("modules/tracker-peerlist.html",
243 peers=[Row(p) for p in peers], percentages=percentages)
244
245
246 class StasyTableModule(UIModule):
247 def _make_percentages(self, items):
248 total = sum(items.values())
249
250 for k in items.keys():
251 items[k] *= 100
252 items[k] /= total
253
254 return items
255
256 def render(self, items, sortby="key", reverse=False, percentage=False, flags=False, locale=False):
257 hundred_percent = 0
258 for v in items.values():
259 hundred_percent += v
260
261 keys = []
262 if sortby == "key":
263 keys = sorted(items.keys(), reverse=reverse)
264 elif sortby == "percentage":
265 keys = [k for k,v in sorted(items.items(), key=operator.itemgetter(1))]
266 if not reverse:
267 keys = reversed(keys)
268 else:
269 raise Exception, "Unknown sortby parameter was provided"
270
271 if hundred_percent:
272 _items = []
273 for k in keys:
274 if not percentage:
275 v = items[k] * 100 / hundred_percent
276 else:
277 v = items[k] * 100
278 _items.append((k, v))
279 items = _items
280
281 if items and type(items[0][0]) == type(()) :
282 _ = self.locale.translate
283 _items = []
284 for k, v in items:
285 k = _("%s to %s") % k
286 _items.append((k, v))
287 items = _items
288
289 if locale:
290 flags = False
291 locales = tornado.locale.LOCALE_NAMES
292 _items = []
293 for k, v in items:
294 if k:
295 for code, locale in locales.items():
296 if code.startswith(k):
297 k = locale["name"].split()[0]
298 _items.append((k, v))
299 items = _items
300
301 return self.render_string("modules/stasy-table.html", items=items, flags=flags)
302
303
304 class StasyCPUCoreTableModule(StasyTableModule):
305 def render(self, items):
306 items = self._make_percentages(items)
307
308 items = items.items()
309 items.sort()
310
311 return self.render_string("modules/stasy-table.html", items=items,
312 flags=None #XXX
313 )
314
315
316 class StasyDeviceTableModule(UIModule):
317 def render(self, devices):
318 groups = {}
319
320 for device in devices:
321 if not groups.has_key(device.cls):
322 groups[device.cls] = []
323
324 groups[device.cls].append(device)
325
326 return self.render_string("modules/stasy-table-devices.html",
327 groups=groups.items())
328
329
330 class StasyGeoTableModule(UIModule):
331 def render(self, items):
332 _ = self.locale.translate
333
334 # Sort all items by value
335 items = sorted(items.items(), key=operator.itemgetter(1), reverse=True)
336
337 countries = []
338 for code, value in items:
339 country = tornado.database.Row({
340 "code" : code.lower(),
341 "name" : _(self.geoip.get_country_name(code)),
342 "value" : value * 100,
343 })
344 countries.append(country)
345
346 return self.render_string("modules/stasy-table-geo.html", countries=countries)
347
348
349 class WishlistModule(UIModule):
350 def render(self, wishes, short=False):
351 return self.render_string("wishlist/modules/wishlist.html",
352 wishes=wishes, short=short)
353
354
355 class WishModule(UIModule):
356 def render(self, wish, short=False):
357 progress_bar = "progress-bar-warning"
358
359 if wish.percentage >= 100:
360 progress_bar = "progress-bar-success"
361
362 return self.render_string("wishlist/modules/wish.html",
363 wish=wish, short=short, progress_bar=progress_bar)
364
365
366 class WishlistItemsModule(UIModule):
367 def render(self, wishlist_items):
368 return self.render_string("modules/wishlist-items.html",
369 wishlist_items=wishlist_items)
370
371
372 class DonationBoxModule(UIModule):
373 def render(self, reason_for_transfer=None, show_wishlist_items=False):
374 if reason_for_transfer:
375 reason_for_transfer = "IPFire.org - %s" % reason_for_transfer
376
377 # Interesting items from the wishlist.
378 wishlist_items = []
379 if show_wishlist_items:
380 wishlist_items = self.wishlist.get_hot_wishes()
381
382 return self.render_string("modules/donation-box.html",
383 reason_for_transfer=reason_for_transfer, wishlist_items=wishlist_items)