]> git.ipfire.org Git - ipfire.org.git/blame - src/web/__init__.py
blog: Correctly redirect back to post after publish
[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
42e745e9 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
35ab4b94
MT
125 # Analytics
126 (r"/analytics", analytics.IndexHandler),
55ed268d 127 (r"/analytics/docs", analytics.DocsHandler),
35ab4b94 128
8505c8cd 129 # Authentication
268a972b 130 (r"/join", auth.JoinHandler),
8505c8cd
MT
131 (r"/login", auth.LoginHandler),
132 (r"/logout", auth.LogoutHandler),
42c7cc66 133 (r"/activate/([a-z_][a-z0-9_-]{0,31})/(\w+)", auth.ActivateHandler),
8505c8cd 134
34472923
MT
135 # Blog
136 (r"/blog", blog.IndexHandler),
34472923
MT
137 (r"/blog/drafts", blog.DraftsHandler),
138 (r"/blog/feed.xml", blog.FeedHandler),
4d657f4f 139 (r"/blog/write", blog.WriteHandler),
feb245e0 140 (r"/blog/years/([0-9]{4})", blog.YearHandler),
34472923
MT
141 (r"/blog/([0-9a-z\-\._]+)", blog.PostHandler),
142 (r"/blog/([0-9a-z\-\._]+)/delete", blog.DeleteHandler),
143 (r"/blog/([0-9a-z\-\._]+)/edit", blog.EditHandler),
144 (r"/blog/([0-9a-z\-\._]+)/publish", blog.PublishHandler),
56801afb 145 (r"/blog/([0-9a-z\-\._]+)/debug/email", blog.DebugEmailHandler),
34472923 146
1958a22b 147 # Docs
5f0d294e 148 (r"/docs/recent\-changes", docs.RecentChangesHandler),
0ce8cc32 149 (r"/docs/search", docs.SearchHandler),
350f391e 150 (r"/docs/tree", docs.TreeHandler),
16619e57 151 (r"/docs/watchlist", docs.WatchlistHandler),
bb998aca 152 (r"/docs/_restore", docs.RestoreHandler),
26ade731 153 (r"/docs/_upload", docs.UploadHandler),
3cfea281
MT
154 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_edit", docs.EditHandler),
155 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_render", docs.RenderHandler),
156 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_(watch|unwatch)", docs.WatchHandler),
107881bb 157 (r"/docs(/[A-Za-z0-9\-_\/]+)?/_files", docs.FilesHandler),
3cfea281
MT
158 (r"/docs(/[A-Za-z0-9\-_\/]+(?:.*)\.(?:\w+))/_delete", docs.DeleteFileHandler),
159 (r"/docs(/[A-Za-z0-9\-_\/]+(?:.*)\.(?:\w+))$", docs.FileHandler),
803f1cc2 160 (r"/docs(/[A-Za-z0-9\-_\/]*)?", docs.PageHandler),
1958a22b 161
aec63a26
MT
162 # Downloads
163 (r"/downloads", downloads.IndexHandler),
930647fc 164 (r"/downloads/cloud", StaticHandler, { "template" : "downloads/cloud.html" }),
aec63a26
MT
165 (r"/downloads/mirrors", downloads.MirrorsHandler),
166 (r"/downloads/thank-you", downloads.ThankYouHandler),
167 (r"/downloads/([0-9a-z\-\.]+)", downloads.ReleaseHandler),
168
e64ce07e 169 # Donate
c7bcb9ca
MT
170 (r"/donate", donate.DonateHandler),
171 (r"/donate/thank-you", donate.ThankYouHandler),
172 (r"/donate/error", donate.ErrorHandler),
d37d6cd2 173 (r"/donate/check-vat-number", donate.CheckVATNumberHandler),
8d48f4ef 174
97e15cf6
MT
175 # Lists
176 (r"/lists", lists.IndexHandler),
177
8066a1e7
MT
178 # Password Reset
179 (r"/password\-reset", auth.PasswordResetInitiationHandler),
180 (r"/password\-reset/([a-z_][a-z0-9_-]{0,31})/(\w+)", auth.PasswordResetHandler),
69a212f3 181 (r"/.well-known/change-password", auth.WellKnownChangePasswordHandler),
8066a1e7 182
d9f7b6e5 183 # Projects
803f1cc2 184 (r"/projects/location/?", location.IndexHandler),
930647fc
MT
185 (r"/projects/location/download", StaticHandler, { "template" : "location/download.html" }),
186 (r"/projects/location/how\-to\-use", StaticHandler, { "template" : "location/how-to-use.html" }),
d9f7b6e5
MT
187 (r"/projects/location/lookup/(.+)", location.LookupHandler),
188
2fe1d960
MT
189 # Single-Sign-On for Discourse
190 (r"/sso/discourse", auth.SSODiscourse),
191
f2c38da0
MT
192 # User Groups
193 (r"/users/groups", users.GroupIndexHandler),
194 (r"/users/groups/([a-z_][a-z0-9_-]{0,31})", users.GroupShowHandler),
195
b01a1ee3 196 # Users
beb13102 197 (r"/users", users.IndexHandler),
53b2117f
MT
198 (r"/users/([a-z_][a-z0-9_-]{0,31})", users.ShowHandler),
199 (r"/users/([a-z_][a-z0-9_-]{0,31})\.jpg", users.AvatarHandler),
1cd4d7d3 200 (r"/users/([a-z_][a-z0-9_-]{0,31})/delete", users.DeleteHandler),
3c986f14 201 (r"/users/([a-z_][a-z0-9_-]{0,31})/edit", users.EditHandler),
e4d2f51f 202 (r"/users/([a-z_][a-z0-9_-]{0,31})/passwd", users.PasswdHandler),
b01a1ee3 203
bb440bad
MT
204 # Promotional Consent Stuff
205 (r"/subscribe", users.SubscribeHandler),
206 (r"/unsubscribe", users.UnsubscribeHandler),
207
4235ba55
MT
208 # VoIP
209 (r"/voip", voip.IndexHandler),
210
45592df5 211 # Static Pages
930647fc
MT
212 (r"/about", StaticHandler, { "template" : "static/about.html" }),
213 (r"/legal", StaticHandler, { "template" : "static/legal.html" }),
214 (r"/help", StaticHandler, { "template" : "static/help.html" }),
215 (r"/sitemap", StaticHandler, { "template" : "static/sitemap.html" }),
45592df5 216
86d86819
MT
217 # API
218 (r"/api/check/email", auth.APICheckEmail),
219 (r"/api/check/uid", auth.APICheckUID),
220
14cd4fa8 221 # Handle old pages that have moved elsewhere
1f153396 222 (r"/blog/authors/(\w+)", tornado.web.RedirectHandler, { "url" : "/users/{0}" }),
7fa7d38d
MT
223 (r"/donation", tornado.web.RedirectHandler, { "url" : "/donate" }),
224 (r"/download", tornado.web.RedirectHandler, { "url" : "/downloads" }),
225 (r"/download/([0-9a-z\-\.]+)", tornado.web.RedirectHandler, { "url" : "/downloads/{0}" }),
85c977e2 226 (r"/features", tornado.web.RedirectHandler, { "url" : "/about" }),
14cd4fa8 227 (r"/imprint", tornado.web.RedirectHandler, { "url" : "/legal" }),
7fa7d38d
MT
228 (r"/news.rss", tornado.web.RedirectHandler, { "url" : "/blog/feed.xml" }),
229 (r"/news/(.*)", tornado.web.RedirectHandler, { "url" : "/blog/{0}" }),
d2000918 230 (r"/support", tornado.web.RedirectHandler, { "url" : "/help"}),
7fa7d38d 231 (r"/(de|en)/(.*)", tornado.web.RedirectHandler, { "url" : "/{0}"}),
37ed7c3c
MT
232
233 # Export arbitrary error pages
b22bc8e8 234 (r"/error/([45][0-9]{2})", base.ErrorHandler),
0ed3ea5c
MT
235
236 # Serve any static files
237 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
940227cb
MT
238 ])
239
34472923 240 # blog.ipfire.org - LEGACY REDIRECTION
c85f80e2 241 self.add_handlers(r"blog\.([a-z]+\.dev\.)?ipfire\.org", [
34472923
MT
242 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog" }),
243 (r"/authors/(\w+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/authors/{0}" }),
244 (r"/post/([0-9a-z\-\._]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/{0}" }),
245 (r"/tags/([0-9a-z\-\.]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/tags/{0}" }),
f0714277
MT
246
247 # RSS Feed
34472923
MT
248 (r"/feed.xml", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/feed.xml" }),
249 ])
12e5de7e 250
940227cb 251 # downloads.ipfire.org
c85f80e2 252 self.add_handlers(r"downloads\.([a-z]+\.dev\.)?ipfire\.org", [
82d4e789 253 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download" }),
450972a3 254 (r"/release/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/{0}" }),
aec63a26 255 (r"/(.*)", downloads.FileHandler),
54af860e 256 ])
940227cb
MT
257
258 # mirrors.ipfire.org
c85f80e2 259 self.add_handlers(r"mirrors\.([a-z]+\.dev\.)?ipfire\.org", [
278b3118
MT
260 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/mirrors" }),
261 (r"/mirrors/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/mirrors/{0}" }),
3808b871 262 ])
940227cb 263
d0d074e0 264 # planet.ipfire.org
c85f80e2 265 self.add_handlers(r"planet\.([a-z]+\.dev\.)?ipfire\.org", [
3d4ce901 266 (r"/", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/" }),
7fa7d38d
MT
267 (r"/post/([A-Za-z0-9_-]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/{0}" }),
268 (r"/user/([a-z0-9_-]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/authors/{0}" }),
bcc3ed4d
MT
269
270 # RSS
f0714277 271 (r"/rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
d76ec66e 272 (r"/user/([a-z0-9_-]+)/rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
f0714277 273 (r"/news.rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
3808b871 274 ])
d0d074e0 275
66862195 276 # fireinfo.ipfire.org
c85f80e2 277 self.add_handlers(r"fireinfo\.([a-z]+\.dev\.)?ipfire\.org", [
96c9bb79 278 (r"/", fireinfo.IndexHandler),
8ab37e0b 279
dc96f754
MT
280 # Admin
281 (r"/admin", fireinfo.AdminIndexHandler),
282
8ab37e0b
MT
283 # Vendors
284 (r"/vendors", fireinfo.VendorsHandler),
285 (r"/vendors/(pci|usb)/([0-9a-f]{4})", fireinfo.VendorHandler),
66862195 286
1e3b2aad 287 # Driver
0cd21a36 288 (r"/drivers/(.*)", fireinfo.DriverDetail),
1e3b2aad 289
66862195 290 # Show profiles
96c9bb79 291 (r"/profile/random", fireinfo.RandomProfileHandler),
b84b407f 292 (r"/profile/([a-z0-9]{40})", fireinfo.ProfileHandler),
91a446f0 293
ed2e3c1f 294 # Stats
19518d6e 295 (r"/processors", fireinfo.ProcessorsHandler),
ed2e3c1f
MT
296 (r"/releases", fireinfo.ReleasesHandler),
297
19518d6e 298 # Send profiles
96c9bb79 299 (r"/send/([a-z0-9]+)", fireinfo.ProfileSendHandler),
0ed3ea5c
MT
300
301 # Serve any static files
302 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
dc96f754 303 ] + authentication_handlers)
5cf160e0 304
c37ec602 305 # i-use.ipfire.org
c85f80e2 306 self.add_handlers(r"i-use\.([a-z]+\.dev\.)?ipfire\.org", [
e2f2865d 307 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/" }),
395c1ac0 308 (r"/profile/([a-f0-9]{40})/([0-9]+).png", iuse.ImageHandler),
c37ec602
MT
309 ])
310
8e2e1261
MT
311 # boot.ipfire.org
312 BOOT_STATIC_PATH = os.path.join(self.settings["static_path"], "netboot")
c85f80e2 313 self.add_handlers(r"boot\.([a-z]+\.dev\.)?ipfire\.org", [
f301d952 314 (r"/", tornado.web.RedirectHandler, { "url" : "https://wiki.ipfire.org/installation/pxe" }),
8e2e1261
MT
315
316 # Configurations
f301d952
MT
317 (r"/premenu.cfg", boot.PremenuCfgHandler),
318 (r"/menu.gpxe", boot.MenuGPXEHandler),
319 (r"/menu.cfg", boot.MenuCfgHandler),
8e2e1261
MT
320
321 # Static files
37b5c0cf 322 (r"/(boot\.png|pxelinux\.0|menu\.c32|vesamenu\.c32)",
8e2e1261
MT
323 tornado.web.StaticFileHandler, { "path" : BOOT_STATIC_PATH }),
324 ])
325
60024cc8 326 # nopaste.ipfire.org
c85f80e2 327 self.add_handlers(r"nopaste\.([a-z]+\.dev\.)?ipfire\.org", [
a41085fb
MT
328 (r"/", nopaste.CreateHandler),
329 (r"/raw/(.*)", nopaste.RawHandler),
330 (r"/view/(.*)", nopaste.ViewHandler),
0ed3ea5c
MT
331
332 # Serve any static files
333 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
3808b871 334 ] + authentication_handlers)
60024cc8 335
f5b01fc2 336 # location.ipfire.org
c85f80e2 337 self.add_handlers(r"location\.([a-z]+\.dev\.)?ipfire\.org", [
42e745e9 338 (r"(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/projects/location{0}" }),
f5b01fc2
MT
339 ])
340
9068dba1 341 # geoip.ipfire.org
c85f80e2 342 self.add_handlers(r"geoip\.([a-z]+\.dev\.)?ipfire\.org", [
f5b01fc2 343 (r"/", tornado.web.RedirectHandler, { "url" : "https://location.ipfire.org/" }),
3808b871 344 ])
9068dba1 345
66862195 346 # talk.ipfire.org
c85f80e2 347 self.add_handlers(r"talk\.([a-z]+\.dev\.)?ipfire\.org", [
786e9ca8
MT
348 (r"/", tornado.web.RedirectHandler, { "url" : "https://people.ipfire.org/" }),
349 ])
66862195 350
03706893 351 # people.ipfire.org
c85f80e2 352 self.add_handlers(r"people\.([a-z]+\.dev\.)?ipfire\.org", [
b6026905 353 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users" }),
268a972b 354 (r"/register", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/join" }),
b6026905
MT
355 (r"/users", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users" }),
356 (r"/users/([a-z_][a-z0-9_-]{0,31})", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users/{0}" }),
357 (r"/users/([a-z_][a-z0-9_-]{0,31})\.jpg", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users/{0}.jpg" }),
358 ])
2cd9af74 359
181d08f3 360 # wiki.ipfire.org
9741abf5 361 self.add_handlers(r"wiki\.([a-z]+\.dev\.)?ipfire\.org", [
42e745e9 362 (r"(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/docs{0}" }),
181d08f3
MT
363 ])
364
ae0228e1 365 # ipfire.org
42e745e9
MT
366 self.add_handlers(r"([a-z]+\.dev\.)?ipfire\.org", [
367 (r".*", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/" })
5cf160e0 368 ])
3add293a 369
feb02477
MT
370 logging.info("Successfully initialied application")
371
574a88c7 372 def format_country_name(self, handler, country_code):
e929ed92 373 return self.backend.get_country_name(country_code)
574a88c7 374
6eddfb50
MT
375 def format_language_name(self, handler, language):
376 _ = handler.locale.translate
377
378 if language == "de":
379 return _("German")
380 elif language == "en":
381 return _("English")
382 elif language == "es":
383 return _("Spanish")
384 elif language == "fr":
385 return _("French")
386 elif language == "it":
387 return _("Italian")
388 elif language == "nl":
389 return _("Dutch")
390 elif language == "pl":
391 return _("Polish")
392 elif language == "pt":
393 return _("Portuguese")
394 elif language == "ru":
395 return _("Russian")
396 elif language == "tr":
397 return _("Turkish")
398
399 return language
400
cc3b928d
MT
401 def format_month_name(self, handler, month):
402 _ = handler.locale.translate
403
404 if month == 1:
405 return _("January")
406 elif month == 2:
407 return _("February")
408 elif month == 3:
409 return _("March")
410 elif month == 4:
411 return _("April")
412 elif month == 5:
413 return _("May")
414 elif month == 6:
415 return _("June")
416 elif month == 7:
417 return _("July")
418 elif month == 8:
419 return _("August")
420 elif month == 9:
421 return _("September")
422 elif month == 10:
423 return _("October")
424 elif month == 11:
425 return _("November")
426 elif month == 12:
427 return _("December")
428
429 return month
401827c2 430
e96e445b
MT
431 def format_phone_number(self, handler, number):
432 if not isinstance(number, phonenumbers.PhoneNumber):
433 try:
01e73b0e 434 number = phonenumbers.parse(number, None)
e96e445b
MT
435 except phonenumbers.phonenumberutil.NumberParseException:
436 return number
c01ad253
MT
437
438 return phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
439
e96e445b
MT
440 def format_phone_number_to_e164(self, handler, number):
441 return phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.E164)
442
443 def format_phone_number_location(self, handler, number):
444 s = [
445 phonenumbers.geocoder.description_for_number(number, handler.locale.code),
446 phonenumbers.region_code_for_number(number),
447 ]
448
449 return ", ".join((e for e in s if e))