add number validation

This commit is contained in:
2026-07-31 23:27:46 +05:00
parent ee8bd5ad52
commit 9074e55a13
+30 -1
View File
@@ -1,3 +1,4 @@
import re
from datetime import datetime
from typing import Literal
@@ -138,6 +139,24 @@ def _normalize_mac(mac: str) -> str:
return mac.strip().upper().replace(":", "-")
_PHONE_ERROR = "Enter a valid phone number"
def _normalize_phone(raw: str) -> str:
"""Validate a Maldivian mobile number and return the 7-digit local form.
Rules: 7 digits, starts with 9 or 7. A 960/+960 country code is stripped ONLY
when the number is 10 digits (960 + 7) — a bare 7-digit number like 9601234 is
a valid local number and is never stripped.
"""
digits = re.sub(r"\D", "", raw or "")
if len(digits) == 10 and digits.startswith("960"):
digits = digits[3:]
if len(digits) == 7 and digits[0] in ("7", "9"):
return digits
raise ValueError(_PHONE_ERROR)
class DeviceOut(BaseModel):
mac_address: str
group: str | None = None # radusergroup.groupname
@@ -151,7 +170,7 @@ class DeviceCreate(BaseModel):
mac_address: str = Field(pattern=_MAC_RE, max_length=17)
group: str = Field(min_length=1, max_length=64)
name: str = Field(min_length=1, max_length=128, description="Customer name (metadata, ignored by RADIUS)")
phone: str = Field(min_length=1, max_length=32, description="Phone number (metadata, ignored by RADIUS)")
phone: str = Field(min_length=1, max_length=32, description="7-digit mobile (9/7…), 960/+960 optional")
alias: str | None = Field(default=None, max_length=64, description="Optional device alias (metadata)")
@field_validator("mac_address")
@@ -159,6 +178,11 @@ class DeviceCreate(BaseModel):
def _norm(cls, v: str) -> str:
return _normalize_mac(v)
@field_validator("phone")
@classmethod
def _norm_phone(cls, v: str) -> str:
return _normalize_phone(v)
class DeviceEdit(BaseModel):
mac_address: str = Field(pattern=_MAC_RE, max_length=17)
@@ -173,6 +197,11 @@ class DeviceEdit(BaseModel):
def _norm(cls, v: str) -> str:
return _normalize_mac(v)
@field_validator("phone")
@classmethod
def _norm_phone(cls, v: str | None) -> str | None:
return None if v is None else _normalize_phone(v)
@model_validator(mode="after")
def _at_least_one(self):
if all(v is None for v in (self.group, self.status, self.name, self.phone, self.alias)):