sync: migrate secure-online-shop to Gitea (2026-08-10)
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, StrictStr, StringConstraints, field_validator
|
||||
|
||||
from app.models.user import RoleEnum
|
||||
|
||||
UsernameField = Annotated[
|
||||
StrictStr,
|
||||
StringConstraints(
|
||||
strip_whitespace=True,
|
||||
min_length=3,
|
||||
max_length=50,
|
||||
),
|
||||
]
|
||||
PasswordField = Annotated[
|
||||
StrictStr,
|
||||
StringConstraints(
|
||||
min_length=8,
|
||||
max_length=72,
|
||||
),
|
||||
]
|
||||
StrongPasswordField = Annotated[
|
||||
StrictStr,
|
||||
StringConstraints(
|
||||
min_length=12,
|
||||
max_length=72,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
username: UsernameField
|
||||
password: StrongPasswordField
|
||||
|
||||
@field_validator("username")
|
||||
@classmethod
|
||||
def normalize_username(cls, value: str) -> str:
|
||||
return value.lower()
|
||||
|
||||
@field_validator("password")
|
||||
@classmethod
|
||||
def validate_password_strength(cls, value: str) -> str:
|
||||
has_upper = any(char.isupper() for char in value)
|
||||
has_lower = any(char.islower() for char in value)
|
||||
has_digit = any(char.isdigit() for char in value)
|
||||
has_special = any(not char.isalnum() for char in value)
|
||||
if not all((has_upper, has_lower, has_digit, has_special)):
|
||||
raise ValueError(
|
||||
"Password must include upper, lower, digit, and special characters"
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
username: UsernameField
|
||||
password: PasswordField
|
||||
|
||||
@field_validator("username")
|
||||
@classmethod
|
||||
def normalize_username(cls, value: str) -> str:
|
||||
return value.lower()
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, extra="forbid")
|
||||
|
||||
id: int
|
||||
username: str
|
||||
role: RoleEnum
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
access_token: str
|
||||
token_type: Literal["bearer"] = "bearer"
|
||||
Reference in New Issue
Block a user