from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field, ValidationInfo, field_validator class FormModel(BaseModel): """Base Pydantic model for HTML form submissions.""" model_config = ConfigDict(extra="forbid", str_strip_whitespace=True) class RegistrationForm(FormModel): username: str = Field(min_length=3, max_length=128) email: str = Field(min_length=5, max_length=255) password: str = Field(min_length=8, max_length=256) confirm_password: str @field_validator("email") @classmethod def validate_email(cls, value: str) -> str: if "@" not in value or value.startswith("@") or value.endswith("@"): raise ValueError("Invalid email address.") local, domain = value.split("@", 1) if not local or "." not in domain: raise ValueError("Invalid email address.") return value.lower() @field_validator("confirm_password") @classmethod def passwords_match(cls, value: str, info: ValidationInfo) -> str: password = info.data.get("password") if password != value: raise ValueError("Passwords do not match.") return value class LoginForm(FormModel): username: str = Field(min_length=1, max_length=255) password: str = Field(min_length=1, max_length=256) class PasswordResetRequestForm(FormModel): email: str = Field(min_length=5, max_length=255) @field_validator("email") @classmethod def validate_email(cls, value: str) -> str: if "@" not in value or value.startswith("@") or value.endswith("@"): raise ValueError("Invalid email address.") local, domain = value.split("@", 1) if not local or "." not in domain: raise ValueError("Invalid email address.") return value.lower() class PasswordResetForm(FormModel): token: str = Field(min_length=1) password: str = Field(min_length=8, max_length=256) confirm_password: str @field_validator("confirm_password") @classmethod def reset_passwords_match(cls, value: str, info: ValidationInfo) -> str: password = info.data.get("password") if password != value: raise ValueError("Passwords do not match.") return value