diff --git a/services/web/server/src/simcore_service_webserver/products/_model.py b/services/web/server/src/simcore_service_webserver/products/_model.py index de3955652a3d..cccd77070081 100644 --- a/services/web/server/src/simcore_service_webserver/products/_model.py +++ b/services/web/server/src/simcore_service_webserver/products/_model.py @@ -111,7 +111,7 @@ class Product(BaseModel): @validator("*", pre=True) @classmethod - def parse_empty_string_as_null(cls, v): + def _parse_empty_string_as_null(cls, v): """Safe measure: database entries are sometimes left blank instead of null""" if isinstance(v, str) and len(v.strip()) == 0: return None @@ -119,12 +119,21 @@ def parse_empty_string_as_null(cls, v): @validator("name", pre=True, always=True) @classmethod - def validate_name(cls, v): + def _validate_name(cls, v): if v not in FRONTEND_APPS_AVAILABLE: msg = f"{v} is not in available front-end apps {FRONTEND_APPS_AVAILABLE}" raise ValueError(msg) return v + @validator("host_regex", pre=True) + @classmethod + def _strip_whitespaces(cls, v): + if v and isinstance(v, str): + # Prevents unintended leading & trailing spaces when added + # manually in the database + return v.strip() + return v + @property def twilio_alpha_numeric_sender_id(self) -> str: return self.short_name or self.display_name.replace(string.punctuation, "")[:11] @@ -132,9 +141,10 @@ def twilio_alpha_numeric_sender_id(self) -> str: class Config: alias_generator = snake_to_camel # to export allow_population_by_field_name = True + anystr_strip_whitespace = True + extra = Extra.ignore frozen = True # read-only orm_mode = True - extra = Extra.ignore schema_extra: ClassVar[dict[str, Any]] = { "examples": [ { diff --git a/services/web/server/tests/unit/isolated/test_products_model.py b/services/web/server/tests/unit/isolated/test_products_model.py index b3ee823a37ea..84fa67d94ebc 100644 --- a/services/web/server/tests/unit/isolated/test_products_model.py +++ b/services/web/server/tests/unit/isolated/test_products_model.py @@ -76,3 +76,22 @@ def test_product_to_static(): ], "isPaymentEnabled": False, } + + +def test_product_host_regex_with_spaces(): + data = Product.Config.schema_extra["examples"][2] + + # with leading and trailing spaces and uppercase (tests anystr_strip_whitespace ) + data["support_email"] = " fOO@BaR.COM " + + # with leading trailing spaces (tests validator("host_regex", pre=True)) + expected = r"([\.-]{0,1}osparc[\.-])".strip() + data["host_regex"] = expected + " " + + # parsing should strip all whitespaces and normalize email + product = Product.parse_obj(data) + + assert product.host_regex.pattern == expected + assert product.host_regex.search("osparc.bar.com") + + assert product.support_email == "foo@bar.com"