]> git.ipfire.org Git - ipfire.org.git/blame - src/web/ui_modules.py
Introduce autotools
[ipfire.org.git] / src / web / 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
494d80e6
MT
16import backend
17
81675874 18class UIModule(tornado.web.UIModule):
940227cb
MT
19 @property
20 def accounts(self):
21 return self.handler.accounts
81675874 22
a0048e66
MT
23 @property
24 def advertisements(self):
25 return self.handler.advertisements
26
d0d074e0 27 @property
940227cb
MT
28 def banners(self):
29 return self.handler.banners
d0d074e0 30
de683d7c
MT
31 @property
32 def memcached(self):
33 return self.handler.memcached
34
940227cb
MT
35 @property
36 def releases(self):
37 return self.handler.releases
81675874 38
638e9782
MT
39 @property
40 def geoip(self):
41 return self.handler.geoip
42
7771acea
MT
43 @property
44 def news(self):
45 return self.handler.news
46
fa7e1a0a
MT
47 @property
48 def planet(self):
49 return self.handler.planet
50
77431b9c
MT
51 @property
52 def talk(self):
53 return self.handler.talk
54
5a1018ab 55
a0048e66
MT
56class AdvertisementModule(UIModule):
57 def render(self, where):
58 assert where in ("download-splash",), where
59
60 ad = self.advertisements.get(where)
61 if not ad:
62 return ""
63
64 # Mark that advert has been shown.
65 ad.update_impressions()
66
67 return self.render_string("modules/ads/%s.html" % where, ad=ad)
68
69
66862195
MT
70class FireinfoDeviceTableModule(UIModule):
71 def render(self, devices):
72 return self.render_string("fireinfo/modules/table-devices.html",
73 devices=devices)
74
75
76class FireinfoDeviceAndGroupsTableModule(UIModule):
77 def render(self, devices):
78 _ = self.locale.translate
79
80 groups = {}
81
82 for device in devices:
83 if not groups.has_key(device.cls):
84 groups[device.cls] = []
85
86 groups[device.cls].append(device)
87
88 # Sort all devices
89 for key in groups.keys():
90 groups[key].sort()
91
92 # Order the groups by their name
93 groups = groups.items()
94 groups.sort()
95
96 return self.render_string("fireinfo/modules/table-devices-and-groups.html",
97 groups=groups)
98
99
100class FireinfoGeoTableModule(UIModule):
101 def render(self, items):
102 countries = []
103 other_countries = []
104 for code, value in items:
105 # Skip the satellite providers in this ranking
106 if code in (None, "A1", "A2"):
107 continue
108
109 name = self.geoip.get_country_name(code)
110
111 # Don't add countries with a small share on the list
112 if value < 0.01:
113 other_countries.append(name)
114 continue
115
494d80e6 116 country = backend.database.Row({
66862195
MT
117 "code" : code,
118 "name" : name,
119 "value" : value,
120 })
121 countries.append(country)
122
66862195
MT
123 return self.render_string("fireinfo/modules/table-geo.html",
124 countries=countries, other_countries=other_countries)
125
126
127class LanguageNameModule(UIModule):
128 def render(self, language):
129 _ = self.locale.translate
130
131 if language == "de":
132 return _("German")
133 elif language == "en":
134 return _("English")
135 elif language == "es":
136 return _("Spanish")
137 elif language == "fr":
138 return _("French")
139 elif language == "it":
140 return _("Italian")
141 elif language == "nl":
142 return _("Dutch")
143 elif language == "pl":
144 return _("Polish")
145 elif language == "pt":
146 return _("Portuguese")
147 elif language == "ru":
148 return _("Russian")
149 elif language == "tr":
150 return _("Turkish")
151
152 return language
153
154
9068dba1
MT
155class MapModule(UIModule):
156 def render(self, latitude, longitude):
157 return self.render_string("modules/map.html", latitude=latitude, longitude=longitude)
158
159
940227cb
MT
160class MenuModule(UIModule):
161 def render(self):
60024cc8 162 return self.render_string("modules/menu.html")
81675874 163
164
9068dba1
MT
165class MirrorItemModule(UIModule):
166 def render(self, item):
167 return self.render_string("modules/mirror-item.html", item=item)
168
169
170class MirrorsTableModule(UIModule):
171 def render(self, mirrors, preferred_mirrors=[]):
172 return self.render_string("modules/mirrors-table.html",
173 mirrors=mirrors, preferred_mirrors=preferred_mirrors)
174
175
176class NetBootMenuConfigModule(UIModule):
37b5c0cf
MT
177 def render(self, release, arch=None, platform=None):
178 return self.render_string("netboot/menu-config.cfg", release=release,
179 arch=arch, platform=platform)
9068dba1
MT
180
181
182class NetBootMenuHeaderModule(UIModule):
37b5c0cf 183 def render(self, title, releases, arch=None, platform=None):
9068dba1
MT
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,
37b5c0cf 189 title=title, releases=releases, arch=arch, platform=platform)
9068dba1
MT
190
191
192class NetBootMenuSeparatorModule(UIModule):
193 def render(self):
194 return self.render_string("netboot/menu-separator.cfg")
195
196
81675874 197class NewsItemModule(UIModule):
940227cb
MT
198 def get_author(self, author):
199 # Get name of author
200 author = self.accounts.find(author)
201 if author:
2fed2438 202 return author.name
940227cb
MT
203 else:
204 _ = self.locale.translate
205 return _("Unknown author")
206
60024cc8 207 def render(self, item, uncut=True, announcement=False, show_heading=True):
940227cb
MT
208 # Get author
209 item.author = self.get_author(item.author_id)
81675874 210
940227cb
MT
211 if not uncut and len(item.text) >= 400:
212 item.text = item.text[:400] + "..."
81675874 213
940227cb 214 # Render text
e46e8df8 215 item.text = textile.textile(item.text.decode("utf8"))
81675874 216
9de13943
MT
217 # Find a release if one exists
218 release = self.releases.get_by_news_id(item.uuid)
219
220 return self.render_string("modules/news-item.html", item=item, release=release,
60024cc8 221 uncut=uncut, announcement=announcement, show_heading=show_heading)
940227cb
MT
222
223
7771acea 224class NewsLineModule(UIModule):
940227cb
MT
225 def render(self, item):
226 return self.render_string("modules/news-line.html", item=item)
227
228
7771acea
MT
229class NewsTableModule(UIModule):
230 def render(self, news):
231 return self.render_string("modules/news-table.html", news=news)
232
233
234class NewsYearNavigationModule(UIModule):
235 def render(self, active=None):
236 try:
237 active = int(active)
238 except:
239 active = None
240
241 return self.render_string("modules/news-year-nav.html",
242 active=active, years=self.news.years)
243
244
fa7e1a0a
MT
245class PlanetSearchBoxModule(UIModule):
246 def render(self, query=None):
60b0917c 247 return self.render_string("modules/planet/search-box.html", query=query)
fa7e1a0a
MT
248
249
81675874 250class SidebarItemModule(UIModule):
251 def render(self):
252 return self.render_string("modules/sidebar-item.html")
253
254
255class SidebarReleaseModule(UIModule):
81675874 256 def render(self):
257 return self.render_string("modules/sidebar-release.html",
940227cb 258 latest=self.releases.get_latest())
81675874 259
260
261class ReleaseItemModule(UIModule):
60024cc8 262 def render(self, release, latest=False):
6371bfda 263 arches = ("x86_64", "i586", "arm")
60024cc8 264
110e8687 265 downloads = []
6371bfda 266 for arch in arches:
110e8687
MT
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))
60024cc8
MT
277
278 return self.render_string("modules/release-item.html",
110e8687 279 release=release, latest=latest, downloads=downloads)
81675874 280
281
282class SidebarBannerModule(UIModule):
940227cb
MT
283 def render(self, item=None):
284 if not item:
285 item = self.banners.get_random()
286
81675874 287 return self.render_string("modules/sidebar-banner.html", item=item)
288
289
60024cc8
MT
290class DownloadButtonModule(UIModule):
291 def render(self, release, text="Download now!"):
292 best_image = None
293
294 for file in release.files:
6371bfda
MT
295 if (release.sname < "ipfire-2.19-core100" or file.arch == "x86_64") \
296 and file.type == "iso":
60024cc8
MT
297 best_image = file
298 break
299
300 # Show nothing when there was no image found.
301 if not best_image:
302 return ""
303
304 return self.render_string("modules/download-button.html",
305 release=release, image=best_image)
306
307
d88b8f41
MT
308class PlanetAuthorBoxModule(UIModule):
309 def render(self, author):
310 return self.render_string("planet/modules/author-box.html", author=author)
311
312
940227cb 313class PlanetEntryModule(UIModule):
60024cc8 314 def render(self, entry, show_avatar=True):
940227cb 315 return self.render_string("modules/planet-entry.html",
60024cc8 316 entry=entry, show_avatar=show_avatar)
d0d074e0
MT
317
318
66862195
MT
319class ProgressBarModule(UIModule):
320 def render(self, value, colour=None):
321 value *= 100
322
323 return self.render_string("modules/progress-bar.html",
324 colour=colour, value=value)
325
326
5ac74b02 327class TalkContactModule(UIModule):
56851b01 328 def render(self, number, name=None, application=None):
5ac74b02
MT
329 account = self.accounts.get_by_sip_id(number)
330
331 return self.render_string("talk/modules/contact.html",
56851b01 332 account=account, number=number, name=name, application=application)
5ac74b02
MT
333
334
66862195 335class TalkCallLogModule(UIModule):
77431b9c
MT
336 def render(self, account=None, viewer=None):
337 if (account is None or not self.current_user == account) \
338 and not self.current_user.is_admin():
339 raise RuntimeException("Insufficient permissions")
340
341 if viewer is None:
342 viewer = self.current_user
343
344 calls = self.talk.get_call_log(account)
345
346 return self.render_string("talk/modules/call-log.html",
347 calls=calls, viewer=viewer)
348
349
350class TalkLinesModule(UIModule):
351 def render(self, account=None, show_account=False):
352 if (account is None or not self.current_user == account) \
353 and not self.current_user.is_admin():
354 raise RuntimeException("Insufficient permissions")
355
356 lines = self.talk.get_lines(account)
357
358 return self.render_string("talk/modules/lines.html",
359 show_account=show_account, lines=lines)
66862195
MT
360
361
362class TalkOngoingCallsModule(UIModule):
5ac74b02 363 def render(self, account=None, debug=False):
77431b9c
MT
364 if (account is None or not self.current_user == account) \
365 and not self.current_user.is_admin():
366 raise RuntimeException("Insufficient permissions")
367
5ac74b02 368 channels = self.talk.get_channels()
77431b9c 369
5ac74b02
MT
370 return self.render_string("talk/modules/ongoing-calls.html",
371 account=account, channels=channels, debug=debug)
66862195
MT
372
373
7771acea 374class DonationBoxModule(UIModule):
e00c06b9 375 def render(self, reason_for_transfer=None):
353880e5
MT
376 if reason_for_transfer:
377 reason_for_transfer = "IPFire.org - %s" % reason_for_transfer
378
379 return self.render_string("modules/donation-box.html",
e00c06b9
MT
380 reason_for_transfer=reason_for_transfer)
381
382
383class DonationButtonModule(UIModule):
069e18f5
MT
384 # https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/
385 COUNTRIES = (
386 "AU",
387 "AT",
388 "BE",
389 "BR",
390 "CA",
391 "CH",
392 "CN",
393 "DE",
394 "ES",
395 "GB",
396 "FR",
397 "IT",
398 "NL",
399 "PL",
400 "PT",
401 "RU",
402 "US",
403 )
404
405 LOCALES = (
406 "da_DK",
407 "he_IL",
408 "id_ID",
409 "ja_JP",
410 "no_NO",
411 "pt_BR",
412 "ru_RU",
413 "sv_SE",
414 "th_TH",
415 "zh_CN",
416 "zh_HK",
417 "zh_TW",
418 )
419
e00c06b9
MT
420 def render(self, reason_for_transfer=None, currency="EUR"):
421 if not reason_for_transfer:
422 reason_for_transfer = "IPFire.org"
423
424 primary = (currency == "EUR")
425
426 return self.render_string("modules/donation-button.html", primary=primary,
069e18f5
MT
427 reason_for_transfer=reason_for_transfer, currency=currency, lc=self.lc)
428
429 @property
430 def lc(self):
431 """
432 Returns the locale of the user
433 """
434 try:
435 locale, delimiter, encoding = self.locale.code.partition(".")
436
437 # Break for languages in specific countries
438 if locale in self.LOCALES:
439 return locale
440
441 lang, delimiter, country_code = locale.partition("_")
069e18f5
MT
442
443 if country_code and country_code in self.COUNTRIES:
444 return country_code
445
446 lang = lang.upper()
447 if lang in self.COUNTRIES:
448 return lang
449 except:
450 pass
451
452 # If anything goes wrong, fall back to GB
453 return "GB"
60b0917c
MT
454
455
456class DonationInputBoxModule(DonationButtonModule):
457 def render(self):
458 currencies = ("EUR", "USD", "GBP", "CHF", "AUD", "NZD", "CAD")
459
460 return self.render_string("modules/donation-input-box.html",
461 currencies=currencies, lc=self.lc)