]> git.ipfire.org Git - ipfire.org.git/blame - src/web/__init__.py
analytics: Show total page views/page views in the last 24h for blog/docs
[ipfire.org.git] / src / web / __init__.py
CommitLineData
81675874 1#/usr/bin/python
2
feb02477 3import logging
81675874 4import os.path
c01ad253 5import phonenumbers
e96e445b 6import phonenumbers.geocoder
81675874 7import tornado.locale
a49b5422 8import tornado.options
81675874 9import tornado.web
10
a95c2f97 11import ipfire
574a88c7 12import ipfire.countries
440aba92 13from .. import util
feb02477 14
11347e46 15from .handlers import *
81675874 16
672be316 17from . import analytics
08df6527 18from . import auth
12e5de7e 19from . import blog
f301d952 20from . import boot
1958a22b 21from . import docs
c7bcb9ca 22from . import donate
aec63a26 23from . import downloads
96c9bb79 24from . import fireinfo
699a0911 25from . import iuse
97e15cf6 26from . import lists
f5b01fc2 27from . import location
a41085fb 28from . import nopaste
df6180a5 29from . import ui_modules
b01a1ee3 30from . import users
4235ba55 31from . import voip
12e5de7e 32
81675874 33class Application(tornado.web.Application):
3e7c6ccd
MT
34 def __init__(self, config, **kwargs):
35 # Initialize backend
a95c2f97 36 self.backend = ipfire.Backend(config)
a6dc0bad 37
9ed02e3b
MT
38 settings = {
39 # Do not compress responses
40 "gzip" : False,
41
42 # Enable XSRF cookies
43 "xsrf_cookies" : True,
44
45 # Login
46 "login_url" : "/login",
47
48 # Setup directory structure
49 "static_path" : self.backend.config.get("global", "static_dir"),
50 "template_path" : self.backend.config.get("global", "templates_dir"),
51
eabe6b8d 52 # UI Methods
9ed02e3b 53 "ui_methods" : {
574a88c7 54 "format_country_name" : self.format_country_name,
6eddfb50 55 "format_language_name" : self.format_language_name,
e96e445b
MT
56 "format_month_name" : self.format_month_name,
57 "format_phone_number" : self.format_phone_number,
58 "format_phone_number_to_e164" : self.format_phone_number_to_e164,
59 "format_phone_number_location" : self.format_phone_number_location,
cc3b928d 60 },
eabe6b8d
MT
61
62 # UI Modules
9ed02e3b 63 "ui_modules" : {
672be316
MT
64 # Analytics
65 "AnalyticsSummary" : analytics.SummaryModule,
66
5806d6fc
MT
67 # Auth
68 "Password" : auth.PasswordModule,
69
f5b01fc2 70 # Blog
7e64f6a3
MT
71 "BlogHistoryNavigation": blog.HistoryNavigationModule,
72 "BlogList" : blog.ListModule,
f91dfcc7 73
93feb275
MT
74 # Boot
75 "BootMenuConfig" : boot.MenuConfigModule,
76 "BootMenuHeader" : boot.MenuHeaderModule,
77 "BootMenuSeparator" : boot.MenuSeparatorModule,
78
cf59466c 79 # Docs
739fff76 80 "DocsDiff" : docs.DiffModule,
cf59466c 81 "DocsHeader" : docs.HeaderModule,
d25f886f 82 "DocsList" : docs.ListModule,
cf59466c 83
e1814f16
MT
84 # Nopaste
85 "Code" : nopaste.CodeModule,
86
23f0179e 87 # Fireinfo
96c9bb79 88 "FireinfoDeviceTable" : fireinfo.DeviceTableModule,
eabe6b8d
MT
89 "FireinfoDeviceAndGroupsTable"
90 : fireinfo.DeviceAndGroupsTableModule,
91
beb13102
MT
92 # Users
93 "UsersList" : users.ListModule,
94
4235ba55 95 # VoIP
214a68a0 96 "VoIPConferences" : voip.ConferencesModule,
00465786
MT
97 "VoIPOutboundRegistrations" :
98 voip.OutboundRegistrationsModule,
8e93325b 99 "VoIPQueues" : voip.QueuesModule,
4235ba55
MT
100 "VoIPRegistrations" : voip.RegistrationsModule,
101
eabe6b8d 102 # Misc
6c6de80a 103 "IPFireLogo" : ui_modules.IPFireLogoModule,
1c4522dc 104 "Markdown" : ui_modules.MarkdownModule,
eabe6b8d
MT
105 "Map" : ui_modules.MapModule,
106 "ProgressBar" : ui_modules.ProgressBarModule,
81675874 107 },
3403dc5e
MT
108
109 # Call this when a page wasn't found
b22bc8e8 110 "default_handler_class" : base.NotFoundHandler,
9ed02e3b 111 }
9068dba1 112 settings.update(kwargs)
5cf160e0 113
ae0228e1
MT
114 tornado.web.Application.__init__(self, **settings)
115
66862195 116 authentication_handlers = [
08df6527
MT
117 (r"/login", auth.LoginHandler),
118 (r"/logout", auth.LogoutHandler),
66862195
MT
119 ]
120
c85f80e2 121 self.add_handlers(r"(www\.)?([a-z]+\.dev\.)?ipfire\.org", [
940227cb
MT
122 # Entry site that lead the user to index
123 (r"/", IndexHandler),
940227cb 124
8505c8cd 125 # Authentication
268a972b 126 (r"/join", auth.JoinHandler),
8505c8cd
MT
127 (r"/login", auth.LoginHandler),
128 (r"/logout", auth.LogoutHandler),
42c7cc66 129 (r"/activate/([a-z_][a-z0-9_-]{0,31})/(\w+)", auth.ActivateHandler),
8505c8cd 130
34472923
MT
131 # Blog
132 (r"/blog", blog.IndexHandler),
34472923
MT
133 (r"/blog/drafts", blog.DraftsHandler),
134 (r"/blog/feed.xml", blog.FeedHandler),
4d657f4f 135 (r"/blog/write", blog.WriteHandler),
feb245e0 136 (r"/blog/years/([0-9]{4})", blog.YearHandler),
34472923
MT
137 (r"/blog/([0-9a-z\-\._]+)", blog.PostHandler),
138 (r"/blog/([0-9a-z\-\._]+)/delete", blog.DeleteHandler),
139 (r"/blog/([0-9a-z\-\._]+)/edit", blog.EditHandler),
140 (r"/blog/([0-9a-z\-\._]+)/publish", blog.PublishHandler),
56801afb 141 (r"/blog/([0-9a-z\-\._]+)/debug/email", blog.DebugEmailHandler),
34472923 142
1958a22b 143 # Docs
5f0d294e 144 (r"/docs/recent\-changes", docs.RecentChangesHandler),
0ce8cc32 145 (r"/docs/search", docs.SearchHandler),
350f391e 146 (r"/docs/tree", docs.TreeHandler),
16619e57 147 (r"/docs/watchlist", docs.WatchlistHandler),
bb998aca 148 (r"/docs/_restore", docs.RestoreHandler),
26ade731 149 (r"/docs/_upload", docs.UploadHandler),
3cfea281
MT
150 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_edit", docs.EditHandler),
151 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_render", docs.RenderHandler),
152 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_(watch|unwatch)", docs.WatchHandler),
107881bb 153 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_files", docs.FilesHandler),
3cfea281
MT
154 (r"/docs(/[A-Za-z0-9\-_\/]+(?:.*)\.(?:\w+))/_delete", docs.DeleteFileHandler),
155 (r"/docs(/[A-Za-z0-9\-_\/]+(?:.*)\.(?:\w+))$", docs.FileHandler),
107881bb 156 (r"/docs(/[A-Za-z0-9\-_\/]+)?", docs.PageHandler),
1958a22b 157
aec63a26
MT
158 # Downloads
159 (r"/downloads", downloads.IndexHandler),
930647fc 160 (r"/downloads/cloud", StaticHandler, { "template" : "downloads/cloud.html" }),
aec63a26
MT
161 (r"/downloads/mirrors", downloads.MirrorsHandler),
162 (r"/downloads/thank-you", downloads.ThankYouHandler),
163 (r"/downloads/([0-9a-z\-\.]+)", downloads.ReleaseHandler),
164
e64ce07e 165 # Donate
c7bcb9ca
MT
166 (r"/donate", donate.DonateHandler),
167 (r"/donate/thank-you", donate.ThankYouHandler),
168 (r"/donate/error", donate.ErrorHandler),
8d48f4ef 169
97e15cf6
MT
170 # Lists
171 (r"/lists", lists.IndexHandler),
172
8066a1e7
MT
173 # Password Reset
174 (r"/password\-reset", auth.PasswordResetInitiationHandler),
175 (r"/password\-reset/([a-z_][a-z0-9_-]{0,31})/(\w+)", auth.PasswordResetHandler),
69a212f3 176 (r"/.well-known/change-password", auth.WellKnownChangePasswordHandler),
8066a1e7 177
d9f7b6e5
MT
178 # Projects
179 (r"/projects/location", location.IndexHandler),
930647fc
MT
180 (r"/projects/location/download", StaticHandler, { "template" : "location/download.html" }),
181 (r"/projects/location/how\-to\-use", StaticHandler, { "template" : "location/how-to-use.html" }),
d9f7b6e5
MT
182 (r"/projects/location/lookup/(.+)", location.LookupHandler),
183
2fe1d960
MT
184 # Single-Sign-On for Discourse
185 (r"/sso/discourse", auth.SSODiscourse),
186
f2c38da0
MT
187 # User Groups
188 (r"/users/groups", users.GroupIndexHandler),
189 (r"/users/groups/([a-z_][a-z0-9_-]{0,31})", users.GroupShowHandler),
190
b01a1ee3 191 # Users
beb13102 192 (r"/users", users.IndexHandler),
53b2117f
MT
193 (r"/users/([a-z_][a-z0-9_-]{0,31})", users.ShowHandler),
194 (r"/users/([a-z_][a-z0-9_-]{0,31})\.jpg", users.AvatarHandler),
1cd4d7d3 195 (r"/users/([a-z_][a-z0-9_-]{0,31})/delete", users.DeleteHandler),
3c986f14 196 (r"/users/([a-z_][a-z0-9_-]{0,31})/edit", users.EditHandler),
e4d2f51f 197 (r"/users/([a-z_][a-z0-9_-]{0,31})/passwd", users.PasswdHandler),
b01a1ee3 198
bb440bad
MT
199 # Promotional Consent Stuff
200 (r"/subscribe", users.SubscribeHandler),
201 (r"/unsubscribe", users.UnsubscribeHandler),
202
4235ba55
MT
203 # VoIP
204 (r"/voip", voip.IndexHandler),
205
45592df5 206 # Static Pages
930647fc
MT
207 (r"/about", StaticHandler, { "template" : "static/about.html" }),
208 (r"/legal", StaticHandler, { "template" : "static/legal.html" }),
209 (r"/help", StaticHandler, { "template" : "static/help.html" }),
210 (r"/sitemap", StaticHandler, { "template" : "static/sitemap.html" }),
45592df5 211
86d86819
MT
212 # API
213 (r"/api/check/email", auth.APICheckEmail),
214 (r"/api/check/uid", auth.APICheckUID),
215
14cd4fa8 216 # Handle old pages that have moved elsewhere
1f153396 217 (r"/blog/authors/(\w+)", tornado.web.RedirectHandler, { "url" : "/users/{0}" }),
7fa7d38d
MT
218 (r"/donation", tornado.web.RedirectHandler, { "url" : "/donate" }),
219 (r"/download", tornado.web.RedirectHandler, { "url" : "/downloads" }),
220 (r"/download/([0-9a-z\-\.]+)", tornado.web.RedirectHandler, { "url" : "/downloads/{0}" }),
85c977e2 221 (r"/features", tornado.web.RedirectHandler, { "url" : "/about" }),
14cd4fa8 222 (r"/imprint", tornado.web.RedirectHandler, { "url" : "/legal" }),
7fa7d38d
MT
223 (r"/news.rss", tornado.web.RedirectHandler, { "url" : "/blog/feed.xml" }),
224 (r"/news/(.*)", tornado.web.RedirectHandler, { "url" : "/blog/{0}" }),
d2000918 225 (r"/support", tornado.web.RedirectHandler, { "url" : "/help"}),
7fa7d38d 226 (r"/(de|en)/(.*)", tornado.web.RedirectHandler, { "url" : "/{0}"}),
37ed7c3c
MT
227
228 # Export arbitrary error pages
b22bc8e8 229 (r"/error/([45][0-9]{2})", base.ErrorHandler),
0ed3ea5c
MT
230
231 # Serve any static files
232 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
940227cb
MT
233 ])
234
34472923 235 # blog.ipfire.org - LEGACY REDIRECTION
c85f80e2 236 self.add_handlers(r"blog\.([a-z]+\.dev\.)?ipfire\.org", [
34472923
MT
237 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog" }),
238 (r"/authors/(\w+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/authors/{0}" }),
239 (r"/post/([0-9a-z\-\._]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/{0}" }),
240 (r"/tags/([0-9a-z\-\.]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/tags/{0}" }),
f0714277
MT
241
242 # RSS Feed
34472923
MT
243 (r"/feed.xml", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/feed.xml" }),
244 ])
12e5de7e 245
940227cb 246 # downloads.ipfire.org
c85f80e2 247 self.add_handlers(r"downloads\.([a-z]+\.dev\.)?ipfire\.org", [
82d4e789 248 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download" }),
450972a3 249 (r"/release/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/{0}" }),
aec63a26 250 (r"/(.*)", downloads.FileHandler),
54af860e 251 ])
940227cb
MT
252
253 # mirrors.ipfire.org
c85f80e2 254 self.add_handlers(r"mirrors\.([a-z]+\.dev\.)?ipfire\.org", [
278b3118
MT
255 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/mirrors" }),
256 (r"/mirrors/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/mirrors/{0}" }),
3808b871 257 ])
940227cb 258
d0d074e0 259 # planet.ipfire.org
c85f80e2 260 self.add_handlers(r"planet\.([a-z]+\.dev\.)?ipfire\.org", [
3d4ce901 261 (r"/", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/" }),
7fa7d38d
MT
262 (r"/post/([A-Za-z0-9_-]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/{0}" }),
263 (r"/user/([a-z0-9_-]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/authors/{0}" }),
bcc3ed4d
MT
264
265 # RSS
f0714277 266 (r"/rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
d76ec66e 267 (r"/user/([a-z0-9_-]+)/rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
f0714277 268 (r"/news.rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
3808b871 269 ])
d0d074e0 270
66862195 271 # fireinfo.ipfire.org
c85f80e2 272 self.add_handlers(r"fireinfo\.([a-z]+\.dev\.)?ipfire\.org", [
96c9bb79 273 (r"/", fireinfo.IndexHandler),
8ab37e0b 274
dc96f754
MT
275 # Admin
276 (r"/admin", fireinfo.AdminIndexHandler),
277
8ab37e0b
MT
278 # Vendors
279 (r"/vendors", fireinfo.VendorsHandler),
280 (r"/vendors/(pci|usb)/([0-9a-f]{4})", fireinfo.VendorHandler),
66862195 281
1e3b2aad 282 # Driver
0cd21a36 283 (r"/drivers/(.*)", fireinfo.DriverDetail),
1e3b2aad 284
66862195 285 # Show profiles
96c9bb79 286 (r"/profile/random", fireinfo.RandomProfileHandler),
b84b407f 287 (r"/profile/([a-z0-9]{40})", fireinfo.ProfileHandler),
91a446f0 288
ed2e3c1f 289 # Stats
19518d6e 290 (r"/processors", fireinfo.ProcessorsHandler),
ed2e3c1f
MT
291 (r"/releases", fireinfo.ReleasesHandler),
292
19518d6e 293 # Send profiles
96c9bb79 294 (r"/send/([a-z0-9]+)", fireinfo.ProfileSendHandler),
0ed3ea5c
MT
295
296 # Serve any static files
297 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
dc96f754 298 ] + authentication_handlers)
5cf160e0 299
c37ec602 300 # i-use.ipfire.org
c85f80e2 301 self.add_handlers(r"i-use\.([a-z]+\.dev\.)?ipfire\.org", [
e2f2865d 302 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/" }),
395c1ac0 303 (r"/profile/([a-f0-9]{40})/([0-9]+).png", iuse.ImageHandler),
c37ec602
MT
304 ])
305
8e2e1261
MT
306 # boot.ipfire.org
307 BOOT_STATIC_PATH = os.path.join(self.settings["static_path"], "netboot")
c85f80e2 308 self.add_handlers(r"boot\.([a-z]+\.dev\.)?ipfire\.org", [
f301d952 309 (r"/", tornado.web.RedirectHandler, { "url" : "https://wiki.ipfire.org/installation/pxe" }),
8e2e1261
MT
310
311 # Configurations
f301d952
MT
312 (r"/premenu.cfg", boot.PremenuCfgHandler),
313 (r"/menu.gpxe", boot.MenuGPXEHandler),
314 (r"/menu.cfg", boot.MenuCfgHandler),
8e2e1261
MT
315
316 # Static files
37b5c0cf 317 (r"/(boot\.png|pxelinux\.0|menu\.c32|vesamenu\.c32)",
8e2e1261
MT
318 tornado.web.StaticFileHandler, { "path" : BOOT_STATIC_PATH }),
319 ])
320
60024cc8 321 # nopaste.ipfire.org
c85f80e2 322 self.add_handlers(r"nopaste\.([a-z]+\.dev\.)?ipfire\.org", [
a41085fb
MT
323 (r"/", nopaste.CreateHandler),
324 (r"/raw/(.*)", nopaste.RawHandler),
325 (r"/view/(.*)", nopaste.ViewHandler),
0ed3ea5c
MT
326
327 # Serve any static files
328 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
3808b871 329 ] + authentication_handlers)
60024cc8 330
f5b01fc2 331 # location.ipfire.org
c85f80e2 332 self.add_handlers(r"location\.([a-z]+\.dev\.)?ipfire\.org", [
d9f7b6e5 333 (r"/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/projects/location/{0}" }),
f5b01fc2
MT
334 ])
335
9068dba1 336 # geoip.ipfire.org
c85f80e2 337 self.add_handlers(r"geoip\.([a-z]+\.dev\.)?ipfire\.org", [
f5b01fc2 338 (r"/", tornado.web.RedirectHandler, { "url" : "https://location.ipfire.org/" }),
3808b871 339 ])
9068dba1 340
66862195 341 # talk.ipfire.org
c85f80e2 342 self.add_handlers(r"talk\.([a-z]+\.dev\.)?ipfire\.org", [
786e9ca8
MT
343 (r"/", tornado.web.RedirectHandler, { "url" : "https://people.ipfire.org/" }),
344 ])
66862195 345
03706893 346 # people.ipfire.org
c85f80e2 347 self.add_handlers(r"people\.([a-z]+\.dev\.)?ipfire\.org", [
b6026905 348 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users" }),
268a972b 349 (r"/register", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/join" }),
b6026905
MT
350 (r"/users", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users" }),
351 (r"/users/([a-z_][a-z0-9_-]{0,31})", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users/{0}" }),
352 (r"/users/([a-z_][a-z0-9_-]{0,31})\.jpg", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users/{0}.jpg" }),
353 ])
2cd9af74 354
181d08f3 355 # wiki.ipfire.org
9741abf5
MT
356 self.add_handlers(r"wiki\.([a-z]+\.dev\.)?ipfire\.org", [
357 (r"/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/docs/{0}" }),
181d08f3
MT
358 ])
359
ae0228e1 360 # ipfire.org
e65b9a6d 361 self.add_handlers(r"(.*)ipfire\.org", [
ba43a892 362 (r".*", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org" })
5cf160e0 363 ])
3add293a 364
feb02477
MT
365 logging.info("Successfully initialied application")
366
574a88c7 367 def format_country_name(self, handler, country_code):
e929ed92 368 return self.backend.get_country_name(country_code)
574a88c7 369
6eddfb50
MT
370 def format_language_name(self, handler, language):
371 _ = handler.locale.translate
372
373 if language == "de":
374 return _("German")
375 elif language == "en":
376 return _("English")
377 elif language == "es":
378 return _("Spanish")
379 elif language == "fr":
380 return _("French")
381 elif language == "it":
382 return _("Italian")
383 elif language == "nl":
384 return _("Dutch")
385 elif language == "pl":
386 return _("Polish")
387 elif language == "pt":
388 return _("Portuguese")
389 elif language == "ru":
390 return _("Russian")
391 elif language == "tr":
392 return _("Turkish")
393
394 return language
395
cc3b928d
MT
396 def format_month_name(self, handler, month):
397 _ = handler.locale.translate
398
399 if month == 1:
400 return _("January")
401 elif month == 2:
402 return _("February")
403 elif month == 3:
404 return _("March")
405 elif month == 4:
406 return _("April")
407 elif month == 5:
408 return _("May")
409 elif month == 6:
410 return _("June")
411 elif month == 7:
412 return _("July")
413 elif month == 8:
414 return _("August")
415 elif month == 9:
416 return _("September")
417 elif month == 10:
418 return _("October")
419 elif month == 11:
420 return _("November")
421 elif month == 12:
422 return _("December")
423
424 return month
401827c2 425
e96e445b
MT
426 def format_phone_number(self, handler, number):
427 if not isinstance(number, phonenumbers.PhoneNumber):
428 try:
01e73b0e 429 number = phonenumbers.parse(number, None)
e96e445b
MT
430 except phonenumbers.phonenumberutil.NumberParseException:
431 return number
c01ad253
MT
432
433 return phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
434
e96e445b
MT
435 def format_phone_number_to_e164(self, handler, number):
436 return phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.E164)
437
438 def format_phone_number_location(self, handler, number):
439 s = [
440 phonenumbers.geocoder.description_for_number(number, handler.locale.code),
441 phonenumbers.region_code_for_number(number),
442 ]
443
444 return ", ".join((e for e in s if e))