Email validation no longer breaks customer retrieval

This commit is contained in:
Jonas Linter
2025-10-14 08:46:16 +02:00
parent 0e659072c0
commit 99d1ed1732
2 changed files with 35 additions and 4 deletions

View File

@@ -1,9 +1,12 @@
import re
import traceback import traceback
from dataclasses import dataclass from dataclasses import dataclass
from datetime import UTC from datetime import UTC
from enum import Enum from enum import Enum
from typing import Any from typing import Any
from email_validator import EmailNotValidError, validate_email
from alpine_bits_python.db import Customer, Reservation from alpine_bits_python.db import Customer, Reservation
from alpine_bits_python.logging_config import get_logger from alpine_bits_python.logging_config import get_logger
from alpine_bits_python.schemas import ( from alpine_bits_python.schemas import (
@@ -618,6 +621,34 @@ def create_res_notif_push_message(
return _create_xml_from_db(list, OtaMessageType.NOTIF, config) return _create_xml_from_db(list, OtaMessageType.NOTIF, config)
def _validate_and_repair_email(email: str | None) -> str | None:
"""Validate and repair email addresses with common typos.
Attempts to fix trailing digits in TLDs (e.g., .de1 -> .de)
before validation. If the email is still invalid, returns None
instead of raising an exception.
Args:
email: Email address to validate and repair
Returns:
Normalized email address or None if invalid
"""
if email is None:
return None
# Remove trailing digits from TLD (e.g., .de1 -> .de, .com2 -> .com)
# This matches a dot followed by letters, then trailing digits at the end
email = re.sub(r'(\.[a-zA-Z]+)\d+$', r'\1', email)
try:
email_info = validate_email(email)
except EmailNotValidError as e:
_LOGGER.warning("invalid email address: %s", e)
return None
return email_info.normalized
def _process_single_reservation( def _process_single_reservation(
reservation: Reservation, reservation: Reservation,
customer: Customer, customer: Customer,

View File

@@ -13,7 +13,6 @@ from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from enum import Enum, IntEnum from enum import Enum, IntEnum
from typing import Any, Optional, override from typing import Any, Optional, override
from zoneinfo import ZoneInfo
from xsdata.formats.dataclass.serializers.config import SerializerConfig from xsdata.formats.dataclass.serializers.config import SerializerConfig
from xsdata_pydantic.bindings import XmlParser, XmlSerializer from xsdata_pydantic.bindings import XmlParser, XmlSerializer
@@ -24,8 +23,7 @@ from alpine_bits_python.alpine_bits_helpers import (
) )
from alpine_bits_python.logging_config import get_logger from alpine_bits_python.logging_config import get_logger
from .db import AckedRequest, Customer, Reservation from .db import Customer, Reservation
from .reservation_service import ReservationService
from .generated.alpinebits import ( from .generated.alpinebits import (
OtaNotifReportRq, OtaNotifReportRq,
OtaNotifReportRs, OtaNotifReportRs,
@@ -34,6 +32,7 @@ from .generated.alpinebits import (
OtaReadRq, OtaReadRq,
WarningStatus, WarningStatus,
) )
from .reservation_service import ReservationService
# Configure logging # Configure logging
_LOGGER = get_logger(__name__) _LOGGER = get_logger(__name__)
@@ -147,7 +146,8 @@ class AlpineBitsResponse:
"""Validate that status code is one of the allowed values.""" """Validate that status code is one of the allowed values."""
if self.status_code not in [200, 400, 401, 500]: if self.status_code not in [200, 400, 401, 500]:
raise ValueError( raise ValueError(
f"Invalid status code {self.status_code}. Must be 200, 400, 401, or 500" "Invalid status code %s. Must be 200, 400, 401, or 500",
self.status_code,
) )