Coverage for baibu/users/phone.py: 100%
12 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-10-06 13:07 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-10-06 13:07 +0000
1"""Phone numbers in international (E.164) format.
3People type numbers with spaces, dashes, dots or brackets, and sometimes
4``00`` instead of ``+``. :func:`normalize_phone` strips that formatting;
5:data:`validate_e164` then checks the result is ``+`` followed by the country
6code and number, at most 15 digits. Numbers in national format (without a
7country code) are refused rather than guessed.
8"""
10import re
12from django.core.validators import RegexValidator
13from django.utils.translation import gettext_lazy as _
15# Characters people commonly use to group digits.
16_FORMATTING = re.compile(r"[\s\-.()/]")
18validate_e164 = RegexValidator(
19 regex=r"^\+[1-9]\d{6,14}$",
20 message=_("Enter a phone number in international format, starting with + and the country code."),
21 code="invalid_phone",
22)
25def normalize_phone(value: str | None) -> str:
26 """Return ``value`` without formatting characters; ``00`` becomes ``+``.
28 The result is not validated; run :data:`validate_e164` on it.
29 """
30 phone = _FORMATTING.sub("", value or "")
31 if phone.startswith("00"):
32 phone = f"+{phone[2:]}"
33 return phone
36def mask_phone(phone: str) -> str:
37 """Hide all but the last two digits, for logs."""
38 return f"...{phone[-2:]}" if len(phone) > 2 else "..."