From 9074e55a13255e952530325406f99a4920dcca43 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Fri, 31 Jul 2026 23:27:46 +0500 Subject: [PATCH] add number validation --- app/schemas.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/app/schemas.py b/app/schemas.py index b803d57..31265c1 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -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)):