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