]> git.ipfire.org Git - ipfire.org.git/blame - src/web/__init__.py
wiki: Only match usernames when a word starts with @
[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
a2864415 198 (r"/location/?", StaticHandler, { "template" : "location/index.html" }),
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 201 (r"/location/how\-to\-use/cli", StaticHandler, { "template" : "location/how-to-use/cli.html" }),
521592f2 202 (r"/location/how\-to\-use/dns", StaticHandler, { "template" : "location/how-to-use/dns.html" }),
d9e4d7b2 203 (r"/location/how\-to\-use/python", StaticHandler, { "template" : "location/how-to-use/python.html" }),
1af3577f 204 (r"/location/install", StaticHandler, { "template" : "location/install.html" }),
f3a102c9 205 (r"/location/report\-a\-problem", StaticHandler, { "template" : "location/report-a-problem.html" }),
a4422469 206 (r"/location/lookup/(.+)", location.LookupHandler),
d9f7b6e5 207
2fe1d960
MT
208 # Single-Sign-On for Discourse
209 (r"/sso/discourse", auth.SSODiscourse),
210
f2c38da0
MT
211 # User Groups
212 (r"/users/groups", users.GroupIndexHandler),
213 (r"/users/groups/([a-z_][a-z0-9_-]{0,31})", users.GroupShowHandler),
214
b01a1ee3 215 # Users
beb13102 216 (r"/users", users.IndexHandler),
53b2117f
MT
217 (r"/users/([a-z_][a-z0-9_-]{0,31})", users.ShowHandler),
218 (r"/users/([a-z_][a-z0-9_-]{0,31})\.jpg", users.AvatarHandler),
1cd4d7d3 219 (r"/users/([a-z_][a-z0-9_-]{0,31})/delete", users.DeleteHandler),
3c986f14 220 (r"/users/([a-z_][a-z0-9_-]{0,31})/edit", users.EditHandler),
e4d2f51f 221 (r"/users/([a-z_][a-z0-9_-]{0,31})/passwd", users.PasswdHandler),
b01a1ee3 222
bb440bad
MT
223 # Promotional Consent Stuff
224 (r"/subscribe", users.SubscribeHandler),
225 (r"/unsubscribe", users.UnsubscribeHandler),
226
4235ba55
MT
227 # VoIP
228 (r"/voip", voip.IndexHandler),
229
45592df5 230 # Static Pages
930647fc
MT
231 (r"/about", StaticHandler, { "template" : "static/about.html" }),
232 (r"/legal", StaticHandler, { "template" : "static/legal.html" }),
233 (r"/help", StaticHandler, { "template" : "static/help.html" }),
8f9e394f 234 (r"/partners", StaticHandler, { "template" : "static/partners.html" }),
930647fc 235 (r"/sitemap", StaticHandler, { "template" : "static/sitemap.html" }),
45592df5 236
86d86819
MT
237 # API
238 (r"/api/check/email", auth.APICheckEmail),
239 (r"/api/check/uid", auth.APICheckUID),
240
14cd4fa8 241 # Handle old pages that have moved elsewhere
1f153396 242 (r"/blog/authors/(\w+)", tornado.web.RedirectHandler, { "url" : "/users/{0}" }),
7fa7d38d
MT
243 (r"/donation", tornado.web.RedirectHandler, { "url" : "/donate" }),
244 (r"/download", tornado.web.RedirectHandler, { "url" : "/downloads" }),
245 (r"/download/([0-9a-z\-\.]+)", tornado.web.RedirectHandler, { "url" : "/downloads/{0}" }),
85c977e2 246 (r"/features", tornado.web.RedirectHandler, { "url" : "/about" }),
14cd4fa8 247 (r"/imprint", tornado.web.RedirectHandler, { "url" : "/legal" }),
7fa7d38d
MT
248 (r"/news.rss", tornado.web.RedirectHandler, { "url" : "/blog/feed.xml" }),
249 (r"/news/(.*)", tornado.web.RedirectHandler, { "url" : "/blog/{0}" }),
7848d387 250 (r"/projects(/.*)", tornado.web.RedirectHandler, { "url" : "{0}" }),
d2000918 251 (r"/support", tornado.web.RedirectHandler, { "url" : "/help"}),
7fa7d38d 252 (r"/(de|en)/(.*)", tornado.web.RedirectHandler, { "url" : "/{0}"}),
37ed7c3c
MT
253
254 # Export arbitrary error pages
b22bc8e8 255 (r"/error/([45][0-9]{2})", base.ErrorHandler),
0ed3ea5c
MT
256
257 # Serve any static files
258 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
940227cb
MT
259 ])
260
34472923 261 # blog.ipfire.org - LEGACY REDIRECTION
c85f80e2 262 self.add_handlers(r"blog\.([a-z]+\.dev\.)?ipfire\.org", [
34472923
MT
263 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog" }),
264 (r"/authors/(\w+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/authors/{0}" }),
265 (r"/post/([0-9a-z\-\._]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/{0}" }),
266 (r"/tags/([0-9a-z\-\.]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/tags/{0}" }),
f0714277
MT
267
268 # RSS Feed
34472923
MT
269 (r"/feed.xml", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/feed.xml" }),
270 ])
12e5de7e 271
940227cb 272 # downloads.ipfire.org
c85f80e2 273 self.add_handlers(r"downloads\.([a-z]+\.dev\.)?ipfire\.org", [
82d4e789 274 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download" }),
450972a3 275 (r"/release/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/{0}" }),
aec63a26 276 (r"/(.*)", downloads.FileHandler),
54af860e 277 ])
940227cb
MT
278
279 # mirrors.ipfire.org
c85f80e2 280 self.add_handlers(r"mirrors\.([a-z]+\.dev\.)?ipfire\.org", [
278b3118
MT
281 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/mirrors" }),
282 (r"/mirrors/(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/download/mirrors/{0}" }),
3808b871 283 ])
940227cb 284
d0d074e0 285 # planet.ipfire.org
c85f80e2 286 self.add_handlers(r"planet\.([a-z]+\.dev\.)?ipfire\.org", [
3d4ce901 287 (r"/", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/" }),
7fa7d38d
MT
288 (r"/post/([A-Za-z0-9_-]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/{0}" }),
289 (r"/user/([a-z0-9_-]+)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/blog/authors/{0}" }),
bcc3ed4d
MT
290
291 # RSS
f0714277 292 (r"/rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
d76ec66e 293 (r"/user/([a-z0-9_-]+)/rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
f0714277 294 (r"/news.rss", tornado.web.RedirectHandler, { "url" : "https://blog.ipfire.org/feed.xml" }),
3808b871 295 ])
d0d074e0 296
945aff38 297 # fireinfo.ipfire.org
c85f80e2 298 self.add_handlers(r"fireinfo\.([a-z]+\.dev\.)?ipfire\.org", [
945aff38 299 # Handle profiles
694f5e0d 300 (r"/send/([a-z0-9]+)", fireinfo.ProfileSendHandler),
f784406c 301
945aff38
MT
302 # Redirect anything else
303 (r"(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/fireinfo{0}" }),
304 ])
5cf160e0 305
c37ec602 306 # i-use.ipfire.org
c85f80e2 307 self.add_handlers(r"i-use\.([a-z]+\.dev\.)?ipfire\.org", [
e2f2865d 308 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/" }),
395c1ac0 309 (r"/profile/([a-f0-9]{40})/([0-9]+).png", iuse.ImageHandler),
c37ec602
MT
310 ])
311
8e2e1261
MT
312 # boot.ipfire.org
313 BOOT_STATIC_PATH = os.path.join(self.settings["static_path"], "netboot")
c85f80e2 314 self.add_handlers(r"boot\.([a-z]+\.dev\.)?ipfire\.org", [
f301d952 315 (r"/", tornado.web.RedirectHandler, { "url" : "https://wiki.ipfire.org/installation/pxe" }),
8e2e1261
MT
316
317 # Configurations
f301d952
MT
318 (r"/premenu.cfg", boot.PremenuCfgHandler),
319 (r"/menu.gpxe", boot.MenuGPXEHandler),
320 (r"/menu.cfg", boot.MenuCfgHandler),
8e2e1261
MT
321
322 # Static files
37b5c0cf 323 (r"/(boot\.png|pxelinux\.0|menu\.c32|vesamenu\.c32)",
8e2e1261
MT
324 tornado.web.StaticFileHandler, { "path" : BOOT_STATIC_PATH }),
325 ])
326
60024cc8 327 # nopaste.ipfire.org
c85f80e2 328 self.add_handlers(r"nopaste\.([a-z]+\.dev\.)?ipfire\.org", [
a41085fb 329 (r"/", nopaste.CreateHandler),
0ad49bfe
MT
330 (r"/upload", nopaste.UploadHandler),
331
332 # View
a41085fb
MT
333 (r"/raw/(.*)", nopaste.RawHandler),
334 (r"/view/(.*)", nopaste.ViewHandler),
0ed3ea5c
MT
335
336 # Serve any static files
337 (r"/static/(.*)", tornado.web.StaticFileHandler, { "path" : self.settings.get("static_path") }),
fbac12cb 338 ] + authentication_handlers)
60024cc8 339
f5b01fc2 340 # location.ipfire.org
c85f80e2 341 self.add_handlers(r"location\.([a-z]+\.dev\.)?ipfire\.org", [
9280d7d1 342 (r"(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/location{0}" }),
f5b01fc2
MT
343 ])
344
9068dba1 345 # geoip.ipfire.org
c85f80e2 346 self.add_handlers(r"geoip\.([a-z]+\.dev\.)?ipfire\.org", [
f5b01fc2 347 (r"/", tornado.web.RedirectHandler, { "url" : "https://location.ipfire.org/" }),
3808b871 348 ])
9068dba1 349
66862195 350 # talk.ipfire.org
c85f80e2 351 self.add_handlers(r"talk\.([a-z]+\.dev\.)?ipfire\.org", [
786e9ca8
MT
352 (r"/", tornado.web.RedirectHandler, { "url" : "https://people.ipfire.org/" }),
353 ])
66862195 354
03706893 355 # people.ipfire.org
c85f80e2 356 self.add_handlers(r"people\.([a-z]+\.dev\.)?ipfire\.org", [
b6026905 357 (r"/", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users" }),
268a972b 358 (r"/register", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/join" }),
b6026905
MT
359 (r"/users", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users" }),
360 (r"/users/([a-z_][a-z0-9_-]{0,31})", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users/{0}" }),
361 (r"/users/([a-z_][a-z0-9_-]{0,31})\.jpg", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/users/{0}.jpg" }),
362 ])
2cd9af74 363
181d08f3 364 # wiki.ipfire.org
9741abf5 365 self.add_handlers(r"wiki\.([a-z]+\.dev\.)?ipfire\.org", [
42e745e9 366 (r"(.*)", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/docs{0}" }),
181d08f3
MT
367 ])
368
ae0228e1 369 # ipfire.org
42e745e9
MT
370 self.add_handlers(r"([a-z]+\.dev\.)?ipfire\.org", [
371 (r".*", tornado.web.RedirectHandler, { "url" : "https://www.ipfire.org/" })
5cf160e0 372 ])
3add293a 373
feb02477
MT
374 logging.info("Successfully initialied application")
375
574a88c7 376 def format_country_name(self, handler, country_code):
e929ed92 377 return self.backend.get_country_name(country_code)
574a88c7 378
6eddfb50
MT
379 def format_language_name(self, handler, language):
380 _ = handler.locale.translate
381
382 if language == "de":
383 return _("German")
384 elif language == "en":
385 return _("English")
386 elif language == "es":
387 return _("Spanish")
388 elif language == "fr":
389 return _("French")
390 elif language == "it":
391 return _("Italian")
392 elif language == "nl":
393 return _("Dutch")
394 elif language == "pl":
395 return _("Polish")
396 elif language == "pt":
397 return _("Portuguese")
398 elif language == "ru":
399 return _("Russian")
400 elif language == "tr":
401 return _("Turkish")
402
403 return language
404
cc3b928d
MT
405 def format_month_name(self, handler, month):
406 _ = handler.locale.translate
407
408 if month == 1:
409 return _("January")
410 elif month == 2:
411 return _("February")
412 elif month == 3:
413 return _("March")
414 elif month == 4:
415 return _("April")
416 elif month == 5:
417 return _("May")
418 elif month == 6:
419 return _("June")
420 elif month == 7:
421 return _("July")
422 elif month == 8:
423 return _("August")
424 elif month == 9:
425 return _("September")
426 elif month == 10:
427 return _("October")
428 elif month == 11:
429 return _("November")
430 elif month == 12:
431 return _("December")
432
433 return month
401827c2 434
e96e445b
MT
435 def format_phone_number(self, handler, number):
436 if not isinstance(number, phonenumbers.PhoneNumber):
437 try:
01e73b0e 438 number = phonenumbers.parse(number, None)
e96e445b
MT
439 except phonenumbers.phonenumberutil.NumberParseException:
440 return number
c01ad253
MT
441
442 return phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
443
e96e445b
MT
444 def format_phone_number_to_e164(self, handler, number):
445 return phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.E164)
446
447 def format_phone_number_location(self, handler, number):
448 s = [
449 phonenumbers.geocoder.description_for_number(number, handler.locale.code),
450 phonenumbers.region_code_for_number(number),
451 ]
452
453 return ", ".join((e for e in s if e))