Skip to content
Snippets Groups Projects
Commit 3ab09461 authored by Mohammad Torkashvand's avatar Mohammad Torkashvand
Browse files

make lat and long string

refactor site validation
parent 7d2fb24d
No related branches found
No related tags found
No related merge requests found
Pipeline #86756 failed
...@@ -20,7 +20,6 @@ from gso.db.models import PartnerTable ...@@ -20,7 +20,6 @@ from gso.db.models import PartnerTable
from gso.products import ProductType from gso.products import ProductType
from gso.products.product_blocks.iptrunk import IptrunkType, PhysicalPortCapacity from gso.products.product_blocks.iptrunk import IptrunkType, PhysicalPortCapacity
from gso.products.product_blocks.router import RouterRole from gso.products.product_blocks.router import RouterRole
from gso.products.product_blocks.site import SiteTier
from gso.services.partners import PartnerNotFoundError, get_partner_by_name from gso.services.partners import PartnerNotFoundError, get_partner_by_name
from gso.services.subscriptions import ( from gso.services.subscriptions import (
get_active_router_subscriptions, get_active_router_subscriptions,
...@@ -36,17 +35,6 @@ app: typer.Typer = typer.Typer() ...@@ -36,17 +35,6 @@ app: typer.Typer = typer.Typer()
class SiteImportModel(BaseSiteValidatorModel): class SiteImportModel(BaseSiteValidatorModel):
"""The required input for importing an existing :class:`gso.products.product_types.site`.""" """The required input for importing an existing :class:`gso.products.product_types.site`."""
site_name: str
site_city: str
site_country: str
site_country_code: str
site_latitude: float
site_longitude: float
site_bgp_community_id: int
site_internal_id: int
site_tier: SiteTier
site_ts_address: str
partner: str
class RouterImportModel(BaseModel): class RouterImportModel(BaseModel):
......
...@@ -5,9 +5,14 @@ from typing import Annotated ...@@ -5,9 +5,14 @@ from typing import Annotated
from orchestrator.domain.base import ProductBlockModel from orchestrator.domain.base import ProductBlockModel
from orchestrator.types import SubscriptionLifecycle, strEnum from orchestrator.types import SubscriptionLifecycle, strEnum
from pydantic import AfterValidator, Field from pydantic import AfterValidator
from typing_extensions import Doc from typing_extensions import Doc
MAX_LONGITUDE = 180
MIN_LONGITUDE = -180
MAX_LATITUDE = 90
MIN_LATITUDE = -90
class SiteTier(strEnum): class SiteTier(strEnum):
"""The tier of a site, ranging from 1 to 4. """The tier of a site, ranging from 1 to 4.
...@@ -22,31 +27,36 @@ class SiteTier(strEnum): ...@@ -22,31 +27,36 @@ class SiteTier(strEnum):
TIER4 = 4 TIER4 = 4
def validate_latitude(v: float) -> float: def validate_latitude(v: str) -> str:
"""Validate a latitude coordinate.""" """Validate a latitude coordinate."""
msg = "Invalid latitude coordinate. Valid examples: '40.7128', '-74.0060', '90', '-90', '0'."
regex = re.compile(r"^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$") regex = re.compile(r"^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$")
if not regex.match(str(v)): if not regex.match(str(v)):
msg = "Invalid latitude coordinate. Valid examples: '40.7128', '-74.0060', '90', '-90', '0'."
raise ValueError(msg) raise ValueError(msg)
float_v = float(v)
if float_v > MAX_LATITUDE or float_v < MIN_LATITUDE:
raise ValueError(msg)
return v return v
def validate_longitude(v: float) -> float: def validate_longitude(v: str) -> str:
"""Validate a longitude coordinate.""" """Validate a longitude coordinate."""
regex = re.compile(r"^-?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$") regex = re.compile(r"^-?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$")
if not regex.match(str(v)): msg = "Invalid longitude coordinate. Valid examples: '40.7128', '-74.0060', '180', '-180', '0'."
msg = "Invalid longitude coordinate. Valid examples: '40.7128', '-74.0060', '180', '-180', '0'." if not regex.match(v):
raise ValueError(msg)
float_v = float(v)
if float_v > MAX_LONGITUDE or float_v < MIN_LONGITUDE:
raise ValueError(msg) raise ValueError(msg)
return v return v
LatitudeCoordinate = Annotated[ LatitudeCoordinate = Annotated[
float, str,
Field(
ge=-90,
le=90,
),
AfterValidator(validate_latitude), AfterValidator(validate_latitude),
Doc( Doc(
"A latitude coordinate, modeled as a string. " "A latitude coordinate, modeled as a string. "
...@@ -56,11 +66,7 @@ LatitudeCoordinate = Annotated[ ...@@ -56,11 +66,7 @@ LatitudeCoordinate = Annotated[
] ]
LongitudeCoordinate = Annotated[ LongitudeCoordinate = Annotated[
float, str,
Field(
ge=-180,
le=180,
),
AfterValidator(validate_longitude), AfterValidator(validate_longitude),
Doc( Doc(
"A longitude coordinate, modeled as a string. " "A longitude coordinate, modeled as a string. "
......
...@@ -213,6 +213,7 @@ class BaseSiteValidatorModel(BaseModel): ...@@ -213,6 +213,7 @@ class BaseSiteValidatorModel(BaseModel):
site_country: str site_country: str
site_latitude: LatitudeCoordinate site_latitude: LatitudeCoordinate
site_longitude: LongitudeCoordinate site_longitude: LongitudeCoordinate
partner: str
@field_validator("site_ts_address") @field_validator("site_ts_address")
def validate_ts_address(cls, site_ts_address: str) -> str: def validate_ts_address(cls, site_ts_address: str) -> str:
......
...@@ -14,6 +14,7 @@ from gso.products.product_blocks.site import LatitudeCoordinate, LongitudeCoordi ...@@ -14,6 +14,7 @@ from gso.products.product_blocks.site import LatitudeCoordinate, LongitudeCoordi
from gso.products.product_types.site import ImportedSiteInactive from gso.products.product_types.site import ImportedSiteInactive
from gso.services import subscriptions from gso.services import subscriptions
from gso.services.partners import get_partner_by_name from gso.services.partners import get_partner_by_name
from gso.utils.helpers import BaseSiteValidatorModel
@step("Create subscription") @step("Create subscription")
...@@ -32,21 +33,9 @@ def create_subscription(partner: str) -> State: ...@@ -32,21 +33,9 @@ def create_subscription(partner: str) -> State:
def generate_initial_input_form() -> FormGenerator: def generate_initial_input_form() -> FormGenerator:
"""Generate a form that is filled in using information passed through the :term:`API` endpoint.""" """Generate a form that is filled in using information passed through the :term:`API` endpoint."""
class ImportSite(FormPage): class ImportSite(FormPage, BaseSiteValidatorModel):
model_config = ConfigDict(title="Import Site") model_config = ConfigDict(title="Import Site")
site_name: str
site_city: str
site_country: str
site_country_code: str
site_latitude: float
site_longitude: float
site_bgp_community_id: int
site_internal_id: int
site_tier: SiteTier
site_ts_address: str
partner: str
user_input = yield ImportSite user_input = yield ImportSite
return user_input.dict() return user_input.dict()
......
...@@ -103,8 +103,8 @@ def site_data(faker, temp_file): ...@@ -103,8 +103,8 @@ def site_data(faker, temp_file):
"site_city": faker.city(), "site_city": faker.city(),
"site_country": faker.country(), "site_country": faker.country(),
"site_country_code": faker.country_code(), "site_country_code": faker.country_code(),
"site_latitude": float(faker.latitude()), "site_latitude": str(faker.latitude()),
"site_longitude": float(faker.longitude()), "site_longitude": str(faker.longitude()),
"site_bgp_community_id": faker.pyint(), "site_bgp_community_id": faker.pyint(),
"site_internal_id": faker.pyint(), "site_internal_id": faker.pyint(),
"site_tier": SiteTier.TIER1, "site_tier": SiteTier.TIER1,
...@@ -228,12 +228,12 @@ def test_import_site_with_invalid_data(mock_start_process, site_data, capfd): ...@@ -228,12 +228,12 @@ def test_import_site_with_invalid_data(mock_start_process, site_data, capfd):
assert "Validation error: 2 validation errors for SiteImportModel" in captured_output assert "Validation error: 2 validation errors for SiteImportModel" in captured_output
assert ( assert (
"""site_latitude """site_latitude
Input should be a valid number [type=float_type, input_value=None, input_type=NoneType]""" Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]"""
in captured_output in captured_output
) )
assert ( assert (
"""site_longitude """site_longitude
Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='broken',""" Value error, Invalid longitude coordinate. Valid examples: '40.7128', '-74.0060', '180', '-180', '0'. [type=value_error, input_value='broken', input_type=str]"""
in captured_output in captured_output
) )
......
...@@ -59,8 +59,8 @@ def site_subscription_factory(faker, geant_partner): ...@@ -59,8 +59,8 @@ def site_subscription_factory(faker, geant_partner):
site_city = site_city or faker.city() site_city = site_city or faker.city()
site_country = site_country or faker.country() site_country = site_country or faker.country()
site_country_code = site_country_code or faker.country_code() site_country_code = site_country_code or faker.country_code()
site_latitude = site_latitude or float(faker.latitude()) site_latitude = site_latitude or str(faker.latitude())
site_longitude = site_longitude or float(faker.longitude()) site_longitude = site_longitude or str(faker.longitude())
site_bgp_community_id = site_bgp_community_id or faker.pyint() site_bgp_community_id = site_bgp_community_id or faker.pyint()
site_internal_id = site_internal_id or faker.pyint() site_internal_id = site_internal_id or faker.pyint()
site_ts_address = site_ts_address or faker.ipv4() site_ts_address = site_ts_address or faker.ipv4()
......
...@@ -15,18 +15,18 @@ class LongitudeModel(BaseModel): ...@@ -15,18 +15,18 @@ class LongitudeModel(BaseModel):
@pytest.mark.parametrize( @pytest.mark.parametrize(
("input_value", "is_valid"), ("input_value", "is_valid"),
[ [
(40.7128, True), ('40.7128', True),
(-74.0060, True), ('-74.0060', True),
(90, True), ('90', True),
(-90, True), ('-90', True),
(0, True), ('0', True),
(45.6, True), ('45.6', True),
(91, False), ('91', False),
(-91, False), ('-91', False),
(180, False), ('180', False),
(-180, False), ('-180', False),
("abc", False), ("abc", False),
(90.1, False), ('90.1', False),
], ],
) )
def test_latitude(input_value, is_valid): def test_latitude(input_value, is_valid):
...@@ -40,16 +40,16 @@ def test_latitude(input_value, is_valid): ...@@ -40,16 +40,16 @@ def test_latitude(input_value, is_valid):
@pytest.mark.parametrize( @pytest.mark.parametrize(
("input_value", "is_valid"), ("input_value", "is_valid"),
[ [
(40.7128, True), ('40.7128', True),
(-74.0060, True), ('-74.0060', True),
(180, True), ('180', True),
(-180, True), ('-180', True),
(0, True), ('0', True),
(90.1, True), ('90.1', True),
(181, False), ('181', False),
(-181, False), ('-181', False),
(200, False), ('200', False),
(-200, False), ('-200', False),
("abc", False), ("abc", False),
("90a", False), ("90a", False),
], ],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment