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