
- Set up project structure with FastAPI and SQLite - Implement user authentication with JWT - Create models for learning content (subjects, lessons, quizzes) - Add progress tracking and gamification features - Implement comprehensive API documentation - Add error handling and validation - Set up proper logging and health check endpoint
89 lines
2.5 KiB
Python
89 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, Type
|
|
|
|
from pydantic import BaseModel, ValidationError
|
|
|
|
from app.core.exceptions import ValidationException
|
|
|
|
|
|
def validate_model(model: Type[BaseModel], data: Dict[str, Any]) -> BaseModel:
|
|
"""
|
|
Validate data against a Pydantic model.
|
|
|
|
Args:
|
|
model: The Pydantic model to validate against
|
|
data: The data to validate
|
|
|
|
Returns:
|
|
The validated model instance
|
|
|
|
Raises:
|
|
ValidationException: If the data fails validation
|
|
"""
|
|
try:
|
|
return model(**data)
|
|
except ValidationError as e:
|
|
errors = e.errors()
|
|
error_details = []
|
|
|
|
for error in errors:
|
|
loc = ".".join(str(x) for x in error["loc"])
|
|
error_details.append(
|
|
{
|
|
"field": loc,
|
|
"message": error["msg"],
|
|
"type": error["type"],
|
|
}
|
|
)
|
|
|
|
raise ValidationException(detail={"errors": error_details})
|
|
|
|
|
|
def validate_password(password: str) -> None:
|
|
"""
|
|
Validate a password meets minimum requirements.
|
|
|
|
Args:
|
|
password: The password to validate
|
|
|
|
Raises:
|
|
ValidationException: If the password is invalid
|
|
"""
|
|
if len(password) < 8:
|
|
raise ValidationException(detail="Password must be at least 8 characters long")
|
|
|
|
if not any(char.isdigit() for char in password):
|
|
raise ValidationException(detail="Password must contain at least one digit")
|
|
|
|
if not any(char.isupper() for char in password):
|
|
raise ValidationException(detail="Password must contain at least one uppercase letter")
|
|
|
|
if not any(char.islower() for char in password):
|
|
raise ValidationException(detail="Password must contain at least one lowercase letter")
|
|
|
|
|
|
def validate_email(email: str) -> None:
|
|
"""
|
|
Validate an email address.
|
|
|
|
Args:
|
|
email: The email address to validate
|
|
|
|
Raises:
|
|
ValidationException: If the email is invalid
|
|
"""
|
|
# Simple check for @ symbol
|
|
if "@" not in email:
|
|
raise ValidationException(detail="Invalid email format")
|
|
|
|
# Split by @ and check parts
|
|
parts = email.split("@")
|
|
if len(parts) != 2 or not parts[0] or not parts[1]:
|
|
raise ValidationException(detail="Invalid email format")
|
|
|
|
# Check for domain with at least one dot
|
|
domain = parts[1]
|
|
if "." not in domain or domain.startswith(".") or domain.endswith("."):
|
|
raise ValidationException(detail="Invalid email domain")
|